n386ld.pas 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178
  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:=getregister32;
  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:=getregister32;
  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:=getregister32;
  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:=getregister32;
  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:=getregister32;
  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(flag_2_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:=getregister32;
  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:=getregister32;
  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. end;
  949. end;
  950. if vtype=$ff then
  951. internalerror(14357);
  952. { write C style pushes or an pascal array }
  953. if nf_cargs in flags then
  954. begin
  955. if vaddr then
  956. begin
  957. emit_to_mem(hp.left.location,hp.left.resulttype.def);
  958. emit_push_lea_loc(hp.left.location,freetemp);
  959. del_reference(hp.left.location.reference);
  960. end
  961. else
  962. emit_push_loc(hp.left.location);
  963. inc(pushedparasize,4);
  964. end
  965. else
  966. begin
  967. { write changing field update href to the next element }
  968. inc(href.offset,4);
  969. if vaddr then
  970. begin
  971. emit_to_mem(hp.left.location,hp.left.resulttype.def);
  972. emit_lea_loc_ref(hp.left.location,href,freetemp);
  973. end
  974. else
  975. begin
  976. emit_mov_loc_ref(hp.left.location,href,S_L,freetemp);
  977. end;
  978. { update href to the vtype field and write it }
  979. dec(href.offset,4);
  980. emit_const_ref(A_MOV,S_L,vtype,newreference(href));
  981. { goto next array element }
  982. inc(href.offset,8);
  983. end;
  984. end
  985. else
  986. { normal array constructor of the same type }
  987. begin
  988. case elesize of
  989. 1 :
  990. emit_mov_loc_ref(hp.left.location,href,S_B,freetemp);
  991. 2 :
  992. emit_mov_loc_ref(hp.left.location,href,S_W,freetemp);
  993. 4 :
  994. emit_mov_loc_ref(hp.left.location,href,S_L,freetemp);
  995. 8 :
  996. begin
  997. if hp.left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  998. begin
  999. emit_reg_ref(A_MOV,S_L,hp.left.location.registerlow,newreference(href));
  1000. { update href to the high bytes and write it }
  1001. inc(href.offset,4);
  1002. emit_reg_ref(A_MOV,S_L,hp.left.location.registerhigh,newreference(href));
  1003. dec(href.offset,4)
  1004. end
  1005. else
  1006. concatcopy(hp.left.location.reference,href,elesize,freetemp,false);
  1007. end;
  1008. else
  1009. begin
  1010. { concatcopy only supports reference }
  1011. if not(hp.left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  1012. internalerror(200108012);
  1013. concatcopy(hp.left.location.reference,href,elesize,freetemp,false);
  1014. end;
  1015. end;
  1016. inc(href.offset,elesize);
  1017. end;
  1018. end;
  1019. { load next entry }
  1020. hp:=tarrayconstructornode(hp.right);
  1021. end;
  1022. end;
  1023. begin
  1024. cloadnode:=ti386loadnode;
  1025. cassignmentnode:=ti386assignmentnode;
  1026. cfuncretnode:=ti386funcretnode;
  1027. carrayconstructornode:=ti386arrayconstructornode;
  1028. end.
  1029. {
  1030. $Log$
  1031. Revision 1.26 2001-11-02 22:58:11 peter
  1032. * procsym definition rewrite
  1033. Revision 1.25 2001/10/28 17:22:25 peter
  1034. * allow assignment of overloaded procedures to procvars when we know
  1035. which procedure to take
  1036. Revision 1.24 2001/10/14 11:49:51 jonas
  1037. * finetuned register allocation info for assignments
  1038. Revision 1.23 2001/10/04 14:33:28 jonas
  1039. * fixed range check errors
  1040. Revision 1.22 2001/09/09 08:51:09 jonas
  1041. * fixed bug with assigning ansistrings (left^.location was released too
  1042. early, caused bug reported by Aleksey V. Vaneev in mailing list on
  1043. 2001/09/07 regarding 'problems with nested procedures and local vars'
  1044. ("merged" from cga.pas in the fixes branch)
  1045. Revision 1.21 2001/08/30 20:13:57 peter
  1046. * rtti/init table updates
  1047. * rttisym for reusable global rtti/init info
  1048. * support published for interfaces
  1049. Revision 1.20 2001/08/30 11:57:20 michael
  1050. + Patch for wrong paramsize
  1051. Revision 1.19 2001/08/26 13:36:59 florian
  1052. * some cg reorganisation
  1053. * some PPC updates
  1054. Revision 1.18 2001/08/06 21:40:50 peter
  1055. * funcret moved from tprocinfo to tprocdef
  1056. Revision 1.17 2001/08/05 13:19:51 peter
  1057. * partly fix for proc of obj=nil
  1058. Revision 1.15 2001/07/28 15:13:17 peter
  1059. * fixed opsize for assignment with LOC_JUMP
  1060. Revision 1.14 2001/05/27 14:30:56 florian
  1061. + some widestring stuff added
  1062. Revision 1.13 2001/04/13 01:22:19 peter
  1063. * symtable change to classes
  1064. * range check generation and errors fixed, make cycle DEBUG=1 works
  1065. * memory leaks fixed
  1066. Revision 1.12 2001/04/02 21:20:37 peter
  1067. * resulttype rewrite
  1068. Revision 1.11 2000/12/25 00:07:33 peter
  1069. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  1070. tlinkedlist objects)
  1071. Revision 1.10 2000/12/05 11:44:33 jonas
  1072. + new integer regvar handling, should be much more efficient
  1073. Revision 1.9 2000/11/29 00:30:48 florian
  1074. * unused units removed from uses clause
  1075. * some changes for widestrings
  1076. Revision 1.8 2000/11/13 14:44:36 jonas
  1077. * fixes so no more range errors with improved range checking code
  1078. Revision 1.7 2000/11/12 23:24:15 florian
  1079. * interfaces are basically running
  1080. Revision 1.6 2000/11/11 22:59:20 florian
  1081. * fixed resourcestrings, made a stupid mistake yesterday
  1082. Revision 1.5 2000/11/09 18:52:06 florian
  1083. * resourcestrings doesn't need the helper anymore they
  1084. access the table now direct
  1085. Revision 1.4 2000/11/06 23:15:02 peter
  1086. * added copyvaluepara call again
  1087. Revision 1.3 2000/11/04 14:25:23 florian
  1088. + merged Attila's changes for interfaces, not tested yet
  1089. Revision 1.2 2000/10/31 22:02:56 peter
  1090. * symtable splitted, no real code changes
  1091. Revision 1.1 2000/10/15 09:33:31 peter
  1092. * moved n386*.pas to i386/ cpu_target dir
  1093. Revision 1.1 2000/10/14 10:14:49 peter
  1094. * moehrendorf oct 2000 rewrite
  1095. }