ncgcal.pas 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate assembler for call nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit ncgcal;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cpubase,
  22. globtype,
  23. parabase,cgutils,
  24. symdef,node,ncal;
  25. type
  26. tcgcallparanode = class(tcallparanode)
  27. private
  28. tempcgpara : tcgpara;
  29. procedure push_addr_para;
  30. procedure push_value_para;
  31. public
  32. constructor create(expr,next : tnode);override;
  33. destructor destroy;override;
  34. procedure secondcallparan;override;
  35. end;
  36. tcgcallnode = class(tcallnode)
  37. private
  38. procedure release_para_temps;
  39. procedure normal_pass_2;
  40. {$ifdef PASS2INLINE}
  41. procedure inlined_pass_2;
  42. {$endif PASS2INLINE}
  43. procedure pushparas;
  44. procedure freeparas;
  45. protected
  46. framepointer_paraloc : tcgpara;
  47. refcountedtemp : treference;
  48. procedure handle_return_value;
  49. {# This routine is used to push the current frame pointer
  50. on the stack. This is used in nested routines where the
  51. value of the frame pointer is always pushed as an extra
  52. parameter.
  53. The default handling is the standard handling used on
  54. most stack based machines, where the frame pointer is
  55. the first invisible parameter.
  56. }
  57. procedure pop_parasize(pop_size:longint);virtual;
  58. procedure extra_interrupt_code;virtual;
  59. procedure extra_call_code;virtual;
  60. procedure extra_post_call_code;virtual;
  61. procedure do_syscall;virtual;abstract;
  62. public
  63. procedure pass_2;override;
  64. end;
  65. implementation
  66. uses
  67. systems,
  68. cutils,verbose,globals,
  69. symconst,symtable,defutil,paramgr,
  70. {$ifdef GDB}
  71. strings,
  72. gdb,
  73. {$endif GDB}
  74. cgbase,pass_2,
  75. aasmbase,aasmtai,
  76. nbas,nmem,nld,ncnv,nutils,
  77. {$ifdef x86}
  78. cga,cgx86,
  79. {$endif x86}
  80. ncgutil,
  81. cgobj,tgobj,
  82. procinfo;
  83. {*****************************************************************************
  84. TCGCALLPARANODE
  85. *****************************************************************************}
  86. constructor tcgcallparanode.create(expr,next : tnode);
  87. begin
  88. inherited create(expr,next);
  89. tempcgpara.init;
  90. end;
  91. destructor tcgcallparanode.destroy;
  92. begin
  93. tempcgpara.done;
  94. inherited destroy;
  95. end;
  96. procedure tcgcallparanode.push_addr_para;
  97. begin
  98. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  99. internalerror(200304235);
  100. cg.a_paramaddr_ref(exprasmlist,left.location.reference,tempcgpara);
  101. end;
  102. procedure tcgcallparanode.push_value_para;
  103. {$ifdef i386}
  104. var
  105. href : treference;
  106. size : longint;
  107. {$endif i386}
  108. begin
  109. { we've nothing to push when the size of the parameter is 0 }
  110. if left.resulttype.def.size=0 then
  111. exit;
  112. { Move flags and jump in register to make it less complex }
  113. if left.location.loc in [LOC_FLAGS,LOC_JUMP] then
  114. location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),false);
  115. { Handle Floating point types differently }
  116. if left.resulttype.def.deftype=floatdef then
  117. begin
  118. {$ifdef i386}
  119. if tempcgpara.location^.loc<>LOC_REFERENCE then
  120. internalerror(200309291);
  121. case left.location.loc of
  122. LOC_FPUREGISTER,
  123. LOC_CFPUREGISTER:
  124. begin
  125. size:=align(TCGSize2Size[left.location.size],tempcgpara.alignment);
  126. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  127. begin
  128. cg.g_stackpointer_alloc(exprasmlist,size);
  129. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  130. end
  131. else
  132. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  133. cg.a_loadfpu_reg_ref(exprasmlist,left.location.size,left.location.register,href);
  134. end;
  135. LOC_MMREGISTER,
  136. LOC_CMMREGISTER:
  137. begin
  138. size:=align(tfloatdef(left.resulttype.def).size,tempcgpara.alignment);
  139. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  140. begin
  141. cg.g_stackpointer_alloc(exprasmlist,size);
  142. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  143. end
  144. else
  145. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  146. cg.a_loadmm_reg_ref(exprasmlist,left.location.size,left.location.size,left.location.register,href,mms_movescalar);
  147. end;
  148. LOC_REFERENCE,
  149. LOC_CREFERENCE :
  150. begin
  151. size:=align(left.resulttype.def.size,tempcgpara.alignment);
  152. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  153. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara)
  154. else
  155. begin
  156. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  157. cg.g_concatcopy(exprasmlist,left.location.reference,href,size);
  158. end;
  159. end;
  160. else
  161. internalerror(2002042430);
  162. end;
  163. {$else i386}
  164. case left.location.loc of
  165. LOC_MMREGISTER,
  166. LOC_CMMREGISTER:
  167. case tempcgpara.location^.loc of
  168. LOC_REFERENCE,
  169. LOC_CREFERENCE,
  170. LOC_MMREGISTER,
  171. LOC_CMMREGISTER:
  172. cg.a_parammm_reg(exprasmlist,left.location.size,left.location.register,tempcgpara,mms_movescalar);
  173. LOC_FPUREGISTER,
  174. LOC_CFPUREGISTER:
  175. begin
  176. location_force_fpureg(exprasmlist,left.location,false);
  177. cg.a_paramfpu_reg(exprasmlist,left.location.size,left.location.register,tempcgpara);
  178. end;
  179. else
  180. internalerror(2002042433);
  181. end;
  182. LOC_FPUREGISTER,
  183. LOC_CFPUREGISTER:
  184. case tempcgpara.location^.loc of
  185. LOC_MMREGISTER,
  186. LOC_CMMREGISTER:
  187. begin
  188. location_force_mmregscalar(exprasmlist,left.location,false);
  189. cg.a_parammm_reg(exprasmlist,left.location.size,left.location.register,tempcgpara,mms_movescalar);
  190. end;
  191. {$ifdef x86_64}
  192. { x86_64 pushes s64comp in normal register }
  193. LOC_REGISTER,
  194. LOC_CREGISTER :
  195. begin
  196. location_force_mem(exprasmlist,left.location);
  197. { force integer size }
  198. left.location.size:=int_cgsize(tcgsize2size[left.location.size]);
  199. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara);
  200. end;
  201. {$endif x86_64}
  202. {$ifdef sparc}
  203. { sparc pushes floats in normal registers }
  204. LOC_REGISTER,
  205. LOC_CREGISTER,
  206. {$endif sparc}
  207. LOC_REFERENCE,
  208. LOC_CREFERENCE,
  209. LOC_FPUREGISTER,
  210. LOC_CFPUREGISTER:
  211. cg.a_paramfpu_reg(exprasmlist,left.location.size,left.location.register,tempcgpara);
  212. else
  213. internalerror(2002042433);
  214. end;
  215. LOC_REFERENCE,
  216. LOC_CREFERENCE:
  217. case tempcgpara.location^.loc of
  218. LOC_MMREGISTER,
  219. LOC_CMMREGISTER:
  220. cg.a_parammm_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara,mms_movescalar);
  221. {$ifdef x86_64}
  222. { x86_64 pushes s64comp in normal register }
  223. LOC_REGISTER,
  224. LOC_CREGISTER :
  225. begin
  226. { force integer size }
  227. left.location.size:=int_cgsize(tcgsize2size[left.location.size]);
  228. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara);
  229. end;
  230. {$endif x86_64}
  231. {$ifdef sparc}
  232. { sparc pushes floats in normal registers }
  233. LOC_REGISTER,
  234. LOC_CREGISTER,
  235. {$endif sparc}
  236. LOC_REFERENCE,
  237. LOC_CREFERENCE,
  238. LOC_FPUREGISTER,
  239. LOC_CFPUREGISTER:
  240. cg.a_paramfpu_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara);
  241. else
  242. internalerror(2002042431);
  243. end;
  244. else
  245. internalerror(2002042432);
  246. end;
  247. {$endif i386}
  248. end
  249. else
  250. begin
  251. case left.location.loc of
  252. LOC_CONSTANT,
  253. LOC_REGISTER,
  254. LOC_CREGISTER,
  255. LOC_REFERENCE,
  256. LOC_CREFERENCE :
  257. begin
  258. {$ifndef cpu64bit}
  259. { use cg64 only for int64, not for 8 byte records }
  260. if is_64bit(left.resulttype.def) then
  261. cg64.a_param64_loc(exprasmlist,left.location,tempcgpara)
  262. else
  263. {$endif cpu64bit}
  264. begin
  265. {$ifndef cpu64bit}
  266. { Only a_param_ref supports multiple locations, when the
  267. value is still a const or in a register then write it
  268. to a reference first. This situation can be triggered
  269. by typecasting an int64 constant to a record of 8 bytes }
  270. if left.location.size in [OS_64,OS_S64] then
  271. location_force_mem(exprasmlist,left.location);
  272. {$endif cpu64bit}
  273. cg.a_param_loc(exprasmlist,left.location,tempcgpara);
  274. end;
  275. end;
  276. {$ifdef SUPPORT_MMX}
  277. LOC_MMXREGISTER,
  278. LOC_CMMXREGISTER:
  279. cg.a_parammm_reg(exprasmlist,OS_M64,left.location.register,tempcgpara,nil);
  280. {$endif SUPPORT_MMX}
  281. else
  282. internalerror(200204241);
  283. end;
  284. end;
  285. end;
  286. procedure tcgcallparanode.secondcallparan;
  287. var
  288. href : treference;
  289. otlabel,
  290. oflabel : tasmlabel;
  291. begin
  292. if not(assigned(parasym)) then
  293. internalerror(200304242);
  294. { Skip nothingn nodes which are used after disabling
  295. a parameter }
  296. if (left.nodetype<>nothingn) then
  297. begin
  298. otlabel:=truelabel;
  299. oflabel:=falselabel;
  300. objectlibrary.getlabel(truelabel);
  301. objectlibrary.getlabel(falselabel);
  302. secondpass(left);
  303. { release memory for refcnt out parameters }
  304. if (parasym.varspez=vs_out) and
  305. (left.resulttype.def.needs_inittable) then
  306. begin
  307. location_get_data_ref(exprasmlist,left.location,href,false);
  308. cg.g_decrrefcount(exprasmlist,left.resulttype.def,href);
  309. end;
  310. {$ifdef PASS2INLINE}
  311. if assigned(aktcallnode.inlinecode) then
  312. paramanager.duplicateparaloc(exprasmlist,aktcallnode.procdefinition.proccalloption,parasym,tempcgpara)
  313. else
  314. {$endif PASS2INLINE}
  315. paramanager.createtempparaloc(exprasmlist,aktcallnode.procdefinition.proccalloption,parasym,tempcgpara);
  316. { handle varargs first, because parasym is not valid }
  317. if (cpf_varargs_para in callparaflags) then
  318. begin
  319. if paramanager.push_addr_param(vs_value,left.resulttype.def,
  320. aktcallnode.procdefinition.proccalloption) then
  321. push_addr_para
  322. else
  323. push_value_para;
  324. end
  325. { hidden parameters }
  326. else if (vo_is_hidden_para in parasym.varoptions) then
  327. begin
  328. { don't push a node that already generated a pointer type
  329. by address for implicit hidden parameters }
  330. if (vo_is_funcret in parasym.varoptions) or
  331. (not(left.resulttype.def.deftype in [pointerdef,classrefdef]) and
  332. paramanager.push_addr_param(parasym.varspez,parasym.vartype.def,
  333. aktcallnode.procdefinition.proccalloption)) then
  334. push_addr_para
  335. else
  336. push_value_para;
  337. end
  338. { formal def }
  339. else if (parasym.vartype.def.deftype=formaldef) then
  340. begin
  341. { allow passing of a constant to a const formaldef }
  342. if (parasym.varspez=vs_const) and
  343. (left.location.loc=LOC_CONSTANT) then
  344. location_force_mem(exprasmlist,left.location);
  345. push_addr_para;
  346. end
  347. { Normal parameter }
  348. else
  349. begin
  350. { don't push a node that already generated a pointer type
  351. by address for implicit hidden parameters }
  352. if (not(
  353. (vo_is_hidden_para in parasym.varoptions) and
  354. (left.resulttype.def.deftype in [pointerdef,classrefdef])
  355. ) and
  356. paramanager.push_addr_param(parasym.varspez,parasym.vartype.def,
  357. aktcallnode.procdefinition.proccalloption)) then
  358. begin
  359. { Passing a var parameter to a var parameter, we can
  360. just push the address transparently }
  361. if (left.nodetype=loadn) and
  362. (tloadnode(left).is_addr_param_load) then
  363. begin
  364. if (left.location.reference.index<>NR_NO) or
  365. (left.location.reference.offset<>0) then
  366. internalerror(200410107);
  367. cg.a_param_reg(exprasmlist,OS_ADDR,left.location.reference.base,tempcgpara)
  368. end
  369. else
  370. begin
  371. { Check for passing a constant to var,out parameter }
  372. if (parasym.varspez in [vs_var,vs_out]) and
  373. (left.location.loc<>LOC_REFERENCE) then
  374. begin
  375. { passing self to a var parameter is allowed in
  376. TP and delphi }
  377. if not((left.location.loc=LOC_CREFERENCE) and
  378. is_self_node(left)) then
  379. internalerror(200106041);
  380. end;
  381. { Force to be in memory }
  382. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  383. location_force_mem(exprasmlist,left.location);
  384. push_addr_para;
  385. end;
  386. end
  387. else
  388. push_value_para;
  389. end;
  390. truelabel:=otlabel;
  391. falselabel:=oflabel;
  392. { update return location in callnode when this is the function
  393. result }
  394. if assigned(parasym) and
  395. (vo_is_funcret in parasym.varoptions) then
  396. location_copy(aktcallnode.location,left.location);
  397. end;
  398. { next parameter }
  399. if assigned(right) then
  400. tcallparanode(right).secondcallparan;
  401. end;
  402. {*****************************************************************************
  403. TCGCALLNODE
  404. *****************************************************************************}
  405. procedure tcgcallnode.extra_interrupt_code;
  406. begin
  407. end;
  408. procedure tcgcallnode.extra_call_code;
  409. begin
  410. end;
  411. procedure tcgcallnode.extra_post_call_code;
  412. begin
  413. end;
  414. procedure tcgcallnode.pop_parasize(pop_size:longint);
  415. begin
  416. end;
  417. procedure tcgcallnode.handle_return_value;
  418. var
  419. cgsize : tcgsize;
  420. retloc : tlocation;
  421. hregister : tregister;
  422. tempnode : tnode;
  423. begin
  424. cgsize:=procdefinition.funcretloc[callerside].size;
  425. { structured results are easy to handle....
  426. needed also when result_no_used !! }
  427. if (procdefinition.proctypeoption<>potype_constructor) and
  428. paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  429. begin
  430. { Location should be setup by the funcret para }
  431. if location.loc<>LOC_REFERENCE then
  432. internalerror(200304241);
  433. end
  434. else
  435. { ansi/widestrings must be registered, so we can dispose them }
  436. if resulttype.def.needs_inittable then
  437. begin
  438. if procdefinition.funcretloc[callerside].loc<>LOC_REGISTER then
  439. internalerror(200409261);
  440. { the FUNCTION_RESULT_REG is already allocated }
  441. if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
  442. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  443. if not assigned(funcretnode) then
  444. begin
  445. { reg_ref could generate two instrcutions and allocate a register so we've to
  446. save the result first before releasing it }
  447. hregister:=cg.getaddressregister(exprasmlist);
  448. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,procdefinition.funcretloc[callerside].register,hregister);
  449. location_reset(location,LOC_REFERENCE,OS_ADDR);
  450. location.reference:=refcountedtemp;
  451. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,location.reference);
  452. end
  453. else
  454. begin
  455. hregister := cg.getaddressregister(exprasmlist);
  456. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,procdefinition.funcretloc[callerside].register,hregister);
  457. { in case of a regular funcretnode with ret_in_param, the }
  458. { original funcretnode isn't touched -> make sure it's }
  459. { the same here (not sure if it's necessary) }
  460. tempnode := funcretnode.getcopy;
  461. tempnode.pass_2;
  462. location := tempnode.location;
  463. tempnode.free;
  464. cg.g_decrrefcount(exprasmlist,resulttype.def,location.reference);
  465. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,location.reference);
  466. end;
  467. end
  468. else
  469. { normal (ordinal,float,pointer) result value }
  470. begin
  471. { we have only to handle the result if it is used }
  472. if (cnf_return_value_used in callnodeflags) then
  473. begin
  474. location.loc:=procdefinition.funcretloc[callerside].loc;
  475. case procdefinition.funcretloc[callerside].loc of
  476. LOC_FPUREGISTER:
  477. begin
  478. location_reset(location,LOC_FPUREGISTER,cgsize);
  479. location.register:=procdefinition.funcretloc[callerside].register;
  480. {$ifdef x86}
  481. tcgx86(cg).inc_fpu_stack;
  482. {$else x86}
  483. if getsupreg(procdefinition.funcretloc[callerside].register)<first_fpu_imreg then
  484. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  485. hregister:=cg.getfpuregister(exprasmlist,location.size);
  486. cg.a_loadfpu_reg_reg(exprasmlist,location.size,location.register,hregister);
  487. location.register:=hregister;
  488. {$endif x86}
  489. end;
  490. LOC_REGISTER:
  491. begin
  492. if cgsize<>OS_NO then
  493. begin
  494. location_reset(location,LOC_REGISTER,cgsize);
  495. {$ifndef cpu64bit}
  496. if cgsize in [OS_64,OS_S64] then
  497. begin
  498. retloc:=procdefinition.funcretloc[callerside];
  499. if retloc.loc<>LOC_REGISTER then
  500. internalerror(200409141);
  501. { the function result registers are already allocated }
  502. if getsupreg(retloc.register64.reglo)<first_int_imreg then
  503. cg.ungetcpuregister(exprasmlist,retloc.register64.reglo);
  504. location.register64.reglo:=cg.getintregister(exprasmlist,OS_32);
  505. cg.a_load_reg_reg(exprasmlist,OS_32,OS_32,retloc.register64.reglo,location.register64.reglo);
  506. if getsupreg(retloc.register64.reghi)<first_int_imreg then
  507. cg.ungetcpuregister(exprasmlist,retloc.register64.reghi);
  508. location.register64.reghi:=cg.getintregister(exprasmlist,OS_32);
  509. cg.a_load_reg_reg(exprasmlist,OS_32,OS_32,retloc.register64.reghi,location.register64.reghi);
  510. end
  511. else
  512. {$endif cpu64bit}
  513. begin
  514. { change register size after the unget because the
  515. getregister was done for the full register
  516. def_cgsize(resulttype.def) is used here because
  517. it could be a constructor call }
  518. if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
  519. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  520. location.register:=cg.getintregister(exprasmlist,def_cgsize(resulttype.def));
  521. cg.a_load_reg_reg(exprasmlist,cgsize,def_cgsize(resulttype.def),procdefinition.funcretloc[callerside].register,location.register);
  522. end;
  523. end
  524. else
  525. begin
  526. if resulttype.def.size>0 then
  527. internalerror(200305131);
  528. end;
  529. end;
  530. LOC_MMREGISTER:
  531. begin
  532. location_reset(location,LOC_MMREGISTER,cgsize);
  533. if getsupreg(procdefinition.funcretloc[callerside].register)<first_mm_imreg then
  534. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  535. location.register:=cg.getmmregister(exprasmlist,cgsize);
  536. cg.a_loadmm_reg_reg(exprasmlist,cgsize,cgsize,procdefinition.funcretloc[callerside].register,location.register,mms_movescalar);
  537. end;
  538. else
  539. internalerror(200405023);
  540. end;
  541. end
  542. else
  543. begin
  544. {$ifdef x86}
  545. { release FPU stack }
  546. if procdefinition.funcretloc[callerside].loc=LOC_FPUREGISTER then
  547. emit_reg(A_FSTP,S_NO,NR_FPU_RESULT_REG);
  548. {$endif x86}
  549. if cgsize<>OS_NO then
  550. location_free(exprasmlist,procdefinition.funcretloc[callerside]);
  551. location_reset(location,LOC_VOID,OS_NO);
  552. end;
  553. end;
  554. { When the result is not used we need to finalize the result and
  555. can release the temp }
  556. if not(cnf_return_value_used in callnodeflags) then
  557. begin
  558. if location.loc=LOC_REFERENCE then
  559. begin
  560. if resulttype.def.needs_inittable then
  561. cg.g_finalize(exprasmlist,resulttype.def,location.reference);
  562. tg.ungetiftemp(exprasmlist,location.reference)
  563. end;
  564. end;
  565. end;
  566. procedure tcgcallnode.release_para_temps;
  567. var
  568. hp : tnode;
  569. ppn : tcallparanode;
  570. begin
  571. { Release temps from parameters }
  572. ppn:=tcallparanode(left);
  573. while assigned(ppn) do
  574. begin
  575. if assigned(ppn.left) then
  576. begin
  577. { don't release the funcret temp }
  578. if not(assigned(ppn.parasym)) or
  579. not(vo_is_funcret in ppn.parasym.varoptions) then
  580. location_freetemp(exprasmlist,ppn.left.location);
  581. { process also all nodes of an array of const }
  582. hp:=ppn.left;
  583. while (hp.nodetype=typeconvn) do
  584. hp:=ttypeconvnode(hp).left;
  585. if (hp.nodetype=arrayconstructorn) and
  586. assigned(tarrayconstructornode(hp).left) then
  587. begin
  588. while assigned(hp) do
  589. begin
  590. location_freetemp(exprasmlist,tarrayconstructornode(hp).left.location);
  591. hp:=tarrayconstructornode(hp).right;
  592. end;
  593. end;
  594. end;
  595. ppn:=tcallparanode(ppn.right);
  596. end;
  597. end;
  598. procedure tcgcallnode.pushparas;
  599. var
  600. ppn : tcgcallparanode;
  601. callerparaloc,
  602. tmpparaloc : pcgparalocation;
  603. sizeleft: aint;
  604. {$ifdef cputargethasfixedstack}
  605. htempref,
  606. href : treference;
  607. {$endif cputargethasfixedstack}
  608. begin
  609. { copy all resources to the allocated registers }
  610. ppn:=tcgcallparanode(left);
  611. while assigned(ppn) do
  612. begin
  613. if (ppn.left.nodetype<>nothingn) then
  614. begin
  615. { better check for the real location of the parameter here, when stack passed parameters
  616. are saved temporary in registers, checking for the tmpparaloc.loc is wrong
  617. }
  618. {$ifdef PASS2INLINE}
  619. if not assigned(inlinecode) then
  620. {$endif PASS2INLINE}
  621. paramanager.freeparaloc(exprasmlist,ppn.tempcgpara);
  622. tmpparaloc:=ppn.tempcgpara.location;
  623. sizeleft:=ppn.tempcgpara.intsize;
  624. callerparaloc:=ppn.parasym.paraloc[callerside].location;
  625. while assigned(callerparaloc) do
  626. begin
  627. { Every paraloc must have a matching tmpparaloc }
  628. if not assigned(tmpparaloc) then
  629. internalerror(200408224);
  630. if callerparaloc^.size<>tmpparaloc^.size then
  631. internalerror(200408225);
  632. case callerparaloc^.loc of
  633. LOC_REGISTER:
  634. begin
  635. if tmpparaloc^.loc<>LOC_REGISTER then
  636. internalerror(200408221);
  637. if getsupreg(callerparaloc^.register)<first_int_imreg then
  638. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  639. cg.a_load_reg_reg(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,
  640. tmpparaloc^.register,callerparaloc^.register);
  641. end;
  642. LOC_FPUREGISTER:
  643. begin
  644. if tmpparaloc^.loc<>LOC_FPUREGISTER then
  645. internalerror(200408222);
  646. if getsupreg(callerparaloc^.register)<first_fpu_imreg then
  647. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  648. cg.a_loadfpu_reg_reg(exprasmlist,ppn.tempcgpara.size,tmpparaloc^.register,callerparaloc^.register);
  649. end;
  650. LOC_MMREGISTER:
  651. begin
  652. if tmpparaloc^.loc<>LOC_MMREGISTER then
  653. internalerror(200408223);
  654. if getsupreg(callerparaloc^.register)<first_mm_imreg then
  655. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  656. cg.a_loadmm_reg_reg(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,
  657. tmpparaloc^.register,callerparaloc^.register,mms_movescalar);
  658. end;
  659. LOC_REFERENCE:
  660. begin
  661. {$ifdef PASS2INLINE}
  662. if not assigned(inlinecode) then
  663. {$endif PASS2INLINE}
  664. begin
  665. {$ifdef cputargethasfixedstack}
  666. { Can't have a data copied to the stack, every location
  667. must contain a valid size field }
  668. if (ppn.tempcgpara.size=OS_NO) and
  669. ((tmpparaloc^.loc<>LOC_REFERENCE) or
  670. assigned(tmpparaloc^.next)) then
  671. internalerror(200501281);
  672. reference_reset_base(href,callerparaloc^.reference.index,callerparaloc^.reference.offset);
  673. { copy parameters in case they were moved to a temp. location because we've a fixed stack }
  674. case tmpparaloc^.loc of
  675. LOC_REFERENCE:
  676. begin
  677. reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset);
  678. { use concatcopy, because it can also be a float which fails when
  679. load_ref_ref is used }
  680. if (ppn.tempcgpara.size <> OS_NO) then
  681. cg.g_concatcopy(exprasmlist,htempref,href,tcgsize2size[tmpparaloc^.size])
  682. else
  683. cg.g_concatcopy(exprasmlist,htempref,href,sizeleft)
  684. end;
  685. LOC_REGISTER:
  686. cg.a_load_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  687. LOC_FPUREGISTER:
  688. cg.a_loadfpu_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.register,href);
  689. LOC_MMREGISTER:
  690. cg.a_loadmm_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href,mms_movescalar);
  691. else
  692. internalerror(200402081);
  693. end;
  694. {$endif cputargethasfixedstack}
  695. end;
  696. end;
  697. end;
  698. dec(sizeleft,tcgsize2size[tmpparaloc^.size]);
  699. callerparaloc:=callerparaloc^.next;
  700. tmpparaloc:=tmpparaloc^.next;
  701. end;
  702. end;
  703. ppn:=tcgcallparanode(ppn.right);
  704. end;
  705. end;
  706. procedure tcgcallnode.freeparas;
  707. var
  708. ppn : tcgcallparanode;
  709. begin
  710. { free the resources allocated for the parameters }
  711. ppn:=tcgcallparanode(left);
  712. while assigned(ppn) do
  713. begin
  714. if (ppn.left.nodetype<>nothingn) then
  715. begin
  716. if
  717. {$ifdef PASS2INLINE}
  718. not assigned(inlinecode) or
  719. {$endif PASS2INLINE}
  720. (ppn.parasym.paraloc[callerside].location^.loc <> LOC_REFERENCE) then
  721. paramanager.freeparaloc(exprasmlist,ppn.parasym.paraloc[callerside]);
  722. end;
  723. ppn:=tcgcallparanode(ppn.right);
  724. end;
  725. end;
  726. procedure tcgcallnode.normal_pass_2;
  727. var
  728. regs_to_save_int,
  729. regs_to_save_fpu,
  730. regs_to_save_mm : Tcpuregisterset;
  731. href : treference;
  732. pop_size : longint;
  733. pvreg,
  734. vmtreg : tregister;
  735. oldaktcallnode : tcallnode;
  736. begin
  737. if not assigned(procdefinition) or
  738. not procdefinition.has_paraloc_info then
  739. internalerror(200305264);
  740. if resulttype.def.needs_inittable and
  741. not paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) and
  742. not assigned(funcretnode) then
  743. begin
  744. tg.gettemptyped(exprasmlist,resulttype.def,tt_normal,refcountedtemp);
  745. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  746. end;
  747. regs_to_save_int:=paramanager.get_volatile_registers_int(procdefinition.proccalloption);
  748. regs_to_save_fpu:=paramanager.get_volatile_registers_fpu(procdefinition.proccalloption);
  749. regs_to_save_mm:=paramanager.get_volatile_registers_mm(procdefinition.proccalloption);
  750. { Include Function result registers }
  751. if (not is_void(resulttype.def)) then
  752. begin
  753. case procdefinition.funcretloc[callerside].loc of
  754. LOC_REGISTER,
  755. LOC_CREGISTER:
  756. include(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  757. LOC_FPUREGISTER,
  758. LOC_CFPUREGISTER:
  759. include(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  760. LOC_MMREGISTER,
  761. LOC_CMMREGISTER:
  762. include(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  763. LOC_REFERENCE,
  764. LOC_VOID:
  765. ;
  766. else
  767. internalerror(2004110213);
  768. end;
  769. end;
  770. { Process parameters, register parameters will be loaded
  771. in imaginary registers. The actual load to the correct
  772. register is done just before the call }
  773. oldaktcallnode:=aktcallnode;
  774. aktcallnode:=self;
  775. if assigned(left) then
  776. tcallparanode(left).secondcallparan;
  777. aktcallnode:=oldaktcallnode;
  778. { procedure variable or normal function call ? }
  779. if (right=nil) then
  780. begin
  781. { When methodpointer is typen we don't need (and can't) load
  782. a pointer. We can directly call the correct procdef (PFV) }
  783. if (po_virtualmethod in procdefinition.procoptions) and
  784. assigned(methodpointer) and
  785. (methodpointer.nodetype<>typen) then
  786. begin
  787. secondpass(methodpointer);
  788. location_force_reg(exprasmlist,methodpointer.location,OS_ADDR,false);
  789. { virtual methods require an index }
  790. if tprocdef(procdefinition).extnumber=$ffff then
  791. internalerror(200304021);
  792. { VMT should already be loaded in a register }
  793. if methodpointer.location.register=NR_NO then
  794. internalerror(200304022);
  795. { test validity of VMT }
  796. if not(is_interface(tprocdef(procdefinition)._class)) and
  797. not(is_cppclass(tprocdef(procdefinition)._class)) then
  798. cg.g_maybe_testvmt(exprasmlist,methodpointer.location.register,tprocdef(procdefinition)._class);
  799. vmtreg:=methodpointer.location.register;
  800. pvreg:=cg.getintregister(exprasmlist,OS_ADDR);
  801. reference_reset_base(href,vmtreg,
  802. tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber));
  803. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,pvreg);
  804. { Load parameters that are in temporary registers in the
  805. correct parameter register }
  806. if assigned(left) then
  807. begin
  808. pushparas;
  809. { free the resources allocated for the parameters }
  810. freeparas;
  811. end;
  812. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  813. if cg.uses_registers(R_FPUREGISTER) then
  814. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  815. if cg.uses_registers(R_MMREGISTER) then
  816. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  817. { call method }
  818. extra_call_code;
  819. cg.a_call_reg(exprasmlist,pvreg);
  820. extra_post_call_code;
  821. end
  822. else
  823. begin
  824. { Load parameters that are in temporary registers in the
  825. correct parameter register }
  826. if assigned(left) then
  827. begin
  828. pushparas;
  829. { free the resources allocated for the parameters }
  830. freeparas;
  831. end;
  832. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  833. if cg.uses_registers(R_FPUREGISTER) then
  834. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  835. if cg.uses_registers(R_MMREGISTER) then
  836. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  837. if procdefinition.proccalloption=pocall_syscall then
  838. do_syscall
  839. else
  840. begin
  841. { Calling interrupt from the same code requires some
  842. extra code }
  843. if (po_interrupt in procdefinition.procoptions) then
  844. extra_interrupt_code;
  845. extra_call_code;
  846. cg.a_call_name(exprasmlist,tprocdef(procdefinition).mangledname);
  847. extra_post_call_code;
  848. end;
  849. end;
  850. end
  851. else
  852. { now procedure variable case }
  853. begin
  854. secondpass(right);
  855. pvreg:=cg.getintregister(exprasmlist,OS_ADDR);
  856. { Only load OS_ADDR from the reference }
  857. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  858. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,right.location.reference,pvreg)
  859. else
  860. cg.a_load_loc_reg(exprasmlist,OS_ADDR,right.location,pvreg);
  861. location_freetemp(exprasmlist,right.location);
  862. { Load parameters that are in temporary registers in the
  863. correct parameter register }
  864. if assigned(left) then
  865. begin
  866. pushparas;
  867. { free the resources allocated for the parameters }
  868. freeparas;
  869. end;
  870. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  871. if cg.uses_registers(R_FPUREGISTER) then
  872. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  873. if cg.uses_registers(R_MMREGISTER) then
  874. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  875. { Calling interrupt from the same code requires some
  876. extra code }
  877. if (po_interrupt in procdefinition.procoptions) then
  878. extra_interrupt_code;
  879. extra_call_code;
  880. cg.a_call_reg(exprasmlist,pvreg);
  881. extra_post_call_code;
  882. end;
  883. { Need to remove the parameters from the stack? }
  884. if (procdefinition.proccalloption in clearstack_pocalls) then
  885. begin
  886. pop_size:=pushedparasize;
  887. { for Cdecl functions we don't need to pop the funcret when it
  888. was pushed by para }
  889. if paramanager.ret_in_param(procdefinition.rettype.def,procdefinition.proccalloption) then
  890. dec(pop_size,sizeof(aint));
  891. { Remove parameters/alignment from the stack }
  892. pop_parasize(pop_size);
  893. end;
  894. { Release registers, but not the registers that contain the
  895. function result }
  896. if (not is_void(resulttype.def)) then
  897. begin
  898. case procdefinition.funcretloc[callerside].loc of
  899. LOC_REGISTER,
  900. LOC_CREGISTER:
  901. begin
  902. {$ifndef cpu64bit}
  903. if procdefinition.funcretloc[callerside].size in [OS_64,OS_S64] then
  904. begin
  905. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register64.reghi));
  906. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register64.reglo));
  907. end
  908. else
  909. {$endif cpu64bit}
  910. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  911. end;
  912. LOC_FPUREGISTER,
  913. LOC_CFPUREGISTER:
  914. exclude(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  915. LOC_MMREGISTER,
  916. LOC_CMMREGISTER:
  917. exclude(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  918. LOC_REFERENCE,
  919. LOC_VOID:
  920. ;
  921. else
  922. internalerror(2004110214);
  923. end;
  924. end;
  925. if cg.uses_registers(R_MMREGISTER) then
  926. cg.dealloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  927. if cg.uses_registers(R_FPUREGISTER) then
  928. cg.dealloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  929. cg.dealloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  930. { handle function results }
  931. if (not is_void(resulttype.def)) then
  932. handle_return_value
  933. else
  934. location_reset(location,LOC_VOID,OS_NO);
  935. { perhaps i/o check ? }
  936. if (cs_check_io in aktlocalswitches) and
  937. (po_iocheck in procdefinition.procoptions) and
  938. not(po_iocheck in current_procinfo.procdef.procoptions) and
  939. { no IO check for methods and procedure variables }
  940. (right=nil) and
  941. not(po_virtualmethod in procdefinition.procoptions) then
  942. begin
  943. cg.allocallcpuregisters(exprasmlist);
  944. cg.a_call_name(exprasmlist,'FPC_IOCHECK');
  945. cg.deallocallcpuregisters(exprasmlist);
  946. end;
  947. { release temps of paras }
  948. release_para_temps;
  949. end;
  950. {$ifdef PASS2INLINE}
  951. procedure tcgcallnode.inlined_pass_2;
  952. var
  953. oldaktcallnode : tcallnode;
  954. oldprocinfo : tprocinfo;
  955. oldinlining_procedure : boolean;
  956. inlineentrycode,inlineexitcode : TAAsmoutput;
  957. {$ifdef GDB}
  958. startlabel,endlabel : tasmlabel;
  959. pp : pchar;
  960. mangled_length : longint;
  961. {$endif GDB}
  962. begin
  963. if not(assigned(procdefinition) and (procdefinition.deftype=procdef)) then
  964. internalerror(200305262);
  965. oldinlining_procedure:=inlining_procedure;
  966. oldprocinfo:=current_procinfo;
  967. { we're inlining a procedure }
  968. inlining_procedure:=true;
  969. { Add inling start }
  970. {$ifdef GDB}
  971. exprasmlist.concat(Tai_force_line.Create);
  972. {$endif GDB}
  973. exprasmList.concat(Tai_Marker.Create(InlineStart));
  974. {$ifdef extdebug}
  975. exprasmList.concat(tai_comment.Create(strpnew('Start of inlined proc '+tprocdef(procdefinition).procsym.name)));
  976. {$endif extdebug}
  977. { calculate registers to pass the parameters }
  978. paramanager.create_inline_paraloc_info(procdefinition);
  979. { Allocate parameters and locals }
  980. gen_alloc_inline_parast(exprasmlist,tprocdef(procdefinition));
  981. gen_alloc_inline_funcret(exprasmlist,tprocdef(procdefinition));
  982. gen_alloc_symtable(exprasmlist,tprocdef(procdefinition).localst);
  983. { if we allocate the temp. location for ansi- or widestrings }
  984. { already here, we avoid later a push/pop }
  985. if resulttype.def.needs_inittable and
  986. not paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  987. begin
  988. tg.gettemptyped(exprasmlist,resulttype.def,tt_normal,refcountedtemp);
  989. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  990. end;
  991. { Push parameters, still use the old current_procinfo. This
  992. is required that have the correct information available like
  993. _class and nested procedure }
  994. oldaktcallnode:=aktcallnode;
  995. aktcallnode:=self;
  996. if assigned(left) then
  997. begin
  998. tcallparanode(left).secondcallparan;
  999. pushparas;
  1000. end;
  1001. aktcallnode:=oldaktcallnode;
  1002. { create temp procinfo that will be used for the inlinecode tree }
  1003. current_procinfo:=cprocinfo.create(nil);
  1004. current_procinfo.procdef:=tprocdef(procdefinition);
  1005. current_procinfo.flags:=oldprocinfo.flags;
  1006. current_procinfo.aktlocaldata.destroy;
  1007. current_procinfo.aktlocaldata:=oldprocinfo.aktlocaldata;
  1008. { when the oldprocinfo is also being inlined reuse the
  1009. inlining_procinfo }
  1010. if assigned(oldprocinfo.inlining_procinfo) then
  1011. current_procinfo.inlining_procinfo:=oldprocinfo.inlining_procinfo
  1012. else
  1013. current_procinfo.inlining_procinfo:=oldprocinfo;
  1014. { takes care of local data initialization }
  1015. inlineentrycode:=TAAsmoutput.Create;
  1016. inlineexitcode:=TAAsmoutput.Create;
  1017. {$ifdef GDB}
  1018. if (cs_debuginfo in aktmoduleswitches) and
  1019. not(cs_gdb_valgrind in aktglobalswitches) then
  1020. begin
  1021. objectlibrary.getaddrlabel(startlabel);
  1022. objectlibrary.getaddrlabel(endlabel);
  1023. cg.a_label(exprasmlist,startlabel);
  1024. { Here we must include the para and local symtable info }
  1025. procdefinition.concatstabto(withdebuglist);
  1026. mangled_length:=length(current_procinfo.inlining_procinfo.procdef.mangledname);
  1027. getmem(pp,mangled_length+50);
  1028. strpcopy(pp,'192,0,0,'+startlabel.name);
  1029. if (target_info.use_function_relative_addresses) then
  1030. begin
  1031. strpcopy(strend(pp),'-');
  1032. strpcopy(strend(pp),current_procinfo.inlining_procinfo.procdef.mangledname);
  1033. end;
  1034. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  1035. end;
  1036. {$endif GDB}
  1037. gen_load_para_value(inlineentrycode);
  1038. { now that we've loaded the para's, free them }
  1039. if assigned(left) then
  1040. freeparas;
  1041. gen_initialize_code(inlineentrycode);
  1042. if po_assembler in current_procinfo.procdef.procoptions then
  1043. inlineentrycode.insert(Tai_marker.Create(asmblockstart));
  1044. exprasmList.concatlist(inlineentrycode);
  1045. { process the inline code }
  1046. secondpass(inlinecode);
  1047. cg.a_label(exprasmlist,current_procinfo.aktexitlabel);
  1048. gen_finalize_code(inlineexitcode);
  1049. gen_load_return_value(inlineexitcode);
  1050. if po_assembler in current_procinfo.procdef.procoptions then
  1051. inlineexitcode.concat(Tai_marker.Create(asmblockend));
  1052. exprasmlist.concatlist(inlineexitcode);
  1053. inlineentrycode.free;
  1054. inlineexitcode.free;
  1055. {$ifdef extdebug}
  1056. exprasmList.concat(tai_comment.Create(strpnew('End of inlined proc')));
  1057. {$endif extdebug}
  1058. exprasmList.concat(Tai_Marker.Create(InlineEnd));
  1059. { handle function results }
  1060. if (not is_void(resulttype.def)) then
  1061. handle_return_value
  1062. else
  1063. location_reset(location,LOC_VOID,OS_NO);
  1064. { perhaps i/o check ? }
  1065. if (cs_check_io in aktlocalswitches) and
  1066. (po_iocheck in procdefinition.procoptions) and
  1067. not(po_iocheck in current_procinfo.procdef.procoptions) and
  1068. { no IO check for methods and procedure variables }
  1069. (right=nil) and
  1070. not(po_virtualmethod in procdefinition.procoptions) then
  1071. begin
  1072. cg.allocallcpuregisters(exprasmlist);
  1073. cg.a_call_name(exprasmlist,'FPC_IOCHECK');
  1074. cg.deallocallcpuregisters(exprasmlist);
  1075. end;
  1076. { release temps of paras }
  1077. release_para_temps;
  1078. { if return value is not used }
  1079. if (not is_void(resulttype.def)) and
  1080. (not(cnf_return_value_used in callnodeflags)) then
  1081. begin
  1082. if location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then
  1083. begin
  1084. { data which must be finalized ? }
  1085. if (resulttype.def.needs_inittable) then
  1086. cg.g_finalize(exprasmlist,resulttype.def,location.reference);
  1087. { release unused temp }
  1088. tg.ungetiftemp(exprasmlist,location.reference)
  1089. end
  1090. else if location.loc=LOC_FPUREGISTER then
  1091. begin
  1092. {$ifdef x86}
  1093. { release FPU stack }
  1094. emit_reg(A_FSTP,S_NO,NR_FPU_RESULT_REG);
  1095. {$endif x86}
  1096. end;
  1097. end;
  1098. { Release parameters and locals }
  1099. gen_free_symtable(exprasmlist,tparasymtable(current_procinfo.procdef.parast));
  1100. gen_free_symtable(exprasmlist,tlocalsymtable(current_procinfo.procdef.localst));
  1101. {$ifdef GDB}
  1102. if (cs_debuginfo in aktmoduleswitches) and
  1103. not(cs_gdb_valgrind in aktglobalswitches) then
  1104. begin
  1105. cg.a_label(exprasmlist,endlabel);
  1106. strpcopy(pp,'224,0,0,'+endlabel.name);
  1107. if (target_info.use_function_relative_addresses) then
  1108. begin
  1109. strpcopy(strend(pp),'-');
  1110. strpcopy(strend(pp),current_procinfo.inlining_procinfo.procdef.mangledname);
  1111. end;
  1112. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  1113. freemem(pp,mangled_length+50);
  1114. end;
  1115. {$endif GDB}
  1116. { restore }
  1117. current_procinfo.aktlocaldata:=nil;
  1118. current_procinfo.destroy;
  1119. current_procinfo:=oldprocinfo;
  1120. inlining_procedure:=oldinlining_procedure;
  1121. end;
  1122. {$endif PASS2INLINE}
  1123. procedure tcgcallnode.pass_2;
  1124. begin
  1125. if assigned(methodpointerinit) then
  1126. secondpass(methodpointerinit);
  1127. {$ifdef PASS2INLINE}
  1128. if assigned(inlinecode) then
  1129. inlined_pass_2
  1130. else
  1131. {$endif PASS2INLINE}
  1132. normal_pass_2;
  1133. if assigned(methodpointerdone) then
  1134. secondpass(methodpointerdone);
  1135. end;
  1136. begin
  1137. ccallparanode:=tcgcallparanode;
  1138. ccallnode:=tcgcallnode;
  1139. end.