ncgcal.pas 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058
  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 pushparas;
  40. procedure freeparas;
  41. protected
  42. framepointer_paraloc : tcgpara;
  43. refcountedtemp : treference;
  44. procedure handle_return_value;
  45. {# This routine is used to push the current frame pointer
  46. on the stack. This is used in nested routines where the
  47. value of the frame pointer is always pushed as an extra
  48. parameter.
  49. The default handling is the standard handling used on
  50. most stack based machines, where the frame pointer is
  51. the first invisible parameter.
  52. }
  53. procedure pop_parasize(pop_size:longint);virtual;
  54. procedure extra_interrupt_code;virtual;
  55. procedure extra_call_code;virtual;
  56. procedure extra_post_call_code;virtual;
  57. procedure do_syscall;virtual;abstract;
  58. public
  59. procedure pass_2;override;
  60. end;
  61. implementation
  62. uses
  63. systems,
  64. cutils,verbose,globals,
  65. symconst,symtable,defutil,paramgr,
  66. cgbase,pass_2,
  67. aasmbase,aasmtai,
  68. nbas,nmem,nld,ncnv,nutils,
  69. {$ifdef x86}
  70. cga,cgx86,
  71. {$endif x86}
  72. ncgutil,
  73. cgobj,tgobj,
  74. procinfo;
  75. {*****************************************************************************
  76. TCGCALLPARANODE
  77. *****************************************************************************}
  78. constructor tcgcallparanode.create(expr,next : tnode);
  79. begin
  80. inherited create(expr,next);
  81. tempcgpara.init;
  82. end;
  83. destructor tcgcallparanode.destroy;
  84. begin
  85. tempcgpara.done;
  86. inherited destroy;
  87. end;
  88. procedure tcgcallparanode.push_addr_para;
  89. begin
  90. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  91. internalerror(200304235);
  92. cg.a_paramaddr_ref(exprasmlist,left.location.reference,tempcgpara);
  93. end;
  94. procedure tcgcallparanode.push_value_para;
  95. {$ifdef i386}
  96. var
  97. href : treference;
  98. size : longint;
  99. {$endif i386}
  100. begin
  101. { we've nothing to push when the size of the parameter is 0 }
  102. if left.resulttype.def.size=0 then
  103. exit;
  104. { Move flags and jump in register to make it less complex }
  105. if left.location.loc in [LOC_FLAGS,LOC_JUMP] then
  106. location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),false);
  107. { Handle Floating point types differently }
  108. if (left.resulttype.def.deftype=floatdef) and not(cs_fp_emulation in aktmoduleswitches) then
  109. begin
  110. {$ifdef i386}
  111. if tempcgpara.location^.loc<>LOC_REFERENCE then
  112. internalerror(200309291);
  113. case left.location.loc of
  114. LOC_FPUREGISTER,
  115. LOC_CFPUREGISTER:
  116. begin
  117. size:=align(TCGSize2Size[left.location.size],tempcgpara.alignment);
  118. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  119. begin
  120. cg.g_stackpointer_alloc(exprasmlist,size);
  121. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  122. end
  123. else
  124. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  125. cg.a_loadfpu_reg_ref(exprasmlist,left.location.size,left.location.register,href);
  126. end;
  127. LOC_MMREGISTER,
  128. LOC_CMMREGISTER:
  129. begin
  130. size:=align(tfloatdef(left.resulttype.def).size,tempcgpara.alignment);
  131. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  132. begin
  133. cg.g_stackpointer_alloc(exprasmlist,size);
  134. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  135. end
  136. else
  137. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  138. cg.a_loadmm_reg_ref(exprasmlist,left.location.size,left.location.size,left.location.register,href,mms_movescalar);
  139. end;
  140. LOC_REFERENCE,
  141. LOC_CREFERENCE :
  142. begin
  143. size:=align(left.resulttype.def.size,tempcgpara.alignment);
  144. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  145. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara)
  146. else
  147. begin
  148. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  149. cg.g_concatcopy(exprasmlist,left.location.reference,href,size);
  150. end;
  151. end;
  152. else
  153. internalerror(2002042430);
  154. end;
  155. {$else i386}
  156. case left.location.loc of
  157. LOC_MMREGISTER,
  158. LOC_CMMREGISTER:
  159. case tempcgpara.location^.loc of
  160. LOC_REFERENCE,
  161. LOC_CREFERENCE,
  162. LOC_MMREGISTER,
  163. LOC_CMMREGISTER:
  164. cg.a_parammm_reg(exprasmlist,left.location.size,left.location.register,tempcgpara,mms_movescalar);
  165. LOC_FPUREGISTER,
  166. LOC_CFPUREGISTER:
  167. begin
  168. location_force_fpureg(exprasmlist,left.location,false);
  169. cg.a_paramfpu_reg(exprasmlist,left.location.size,left.location.register,tempcgpara);
  170. end;
  171. else
  172. internalerror(200204249);
  173. end;
  174. LOC_FPUREGISTER,
  175. LOC_CFPUREGISTER:
  176. case tempcgpara.location^.loc of
  177. LOC_MMREGISTER,
  178. LOC_CMMREGISTER:
  179. begin
  180. location_force_mmregscalar(exprasmlist,left.location,false);
  181. cg.a_parammm_reg(exprasmlist,left.location.size,left.location.register,tempcgpara,mms_movescalar);
  182. end;
  183. {$ifdef x86_64}
  184. { x86_64 pushes s64comp in normal register }
  185. LOC_REGISTER,
  186. LOC_CREGISTER :
  187. begin
  188. location_force_mem(exprasmlist,left.location);
  189. { force integer size }
  190. left.location.size:=int_cgsize(tcgsize2size[left.location.size]);
  191. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara);
  192. end;
  193. {$endif x86_64}
  194. {$ifdef powerpc}
  195. LOC_REGISTER,
  196. LOC_CREGISTER :
  197. begin
  198. { aix abi passes floats of varargs in both fpu and }
  199. { integer registers }
  200. location_force_mem(exprasmlist,left.location);
  201. { force integer size }
  202. left.location.size:=int_cgsize(tcgsize2size[left.location.size]);
  203. if (left.location.size in [OS_32,OS_S32]) then
  204. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara)
  205. else
  206. cg64.a_param64_ref(exprasmlist,left.location.reference,tempcgpara);
  207. end;
  208. {$endif powerpc}
  209. {$if defined(sparc) or defined(arm)}
  210. { sparc and arm pass floats in normal registers }
  211. LOC_REGISTER,
  212. LOC_CREGISTER,
  213. {$endif sparc}
  214. LOC_REFERENCE,
  215. LOC_CREFERENCE,
  216. LOC_FPUREGISTER,
  217. LOC_CFPUREGISTER:
  218. cg.a_paramfpu_reg(exprasmlist,left.location.size,left.location.register,tempcgpara);
  219. else
  220. internalerror(2002042433);
  221. end;
  222. LOC_REFERENCE,
  223. LOC_CREFERENCE:
  224. case tempcgpara.location^.loc of
  225. LOC_MMREGISTER,
  226. LOC_CMMREGISTER:
  227. cg.a_parammm_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara,mms_movescalar);
  228. {$ifdef x86_64}
  229. { x86_64 pushes s64comp in normal register }
  230. LOC_REGISTER,
  231. LOC_CREGISTER :
  232. begin
  233. { force integer size }
  234. left.location.size:=int_cgsize(tcgsize2size[left.location.size]);
  235. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara);
  236. end;
  237. {$endif x86_64}
  238. {$ifdef powerpc}
  239. { x86_64 pushes s64comp in normal register }
  240. LOC_REGISTER,
  241. LOC_CREGISTER :
  242. begin
  243. { force integer size }
  244. left.location.size:=int_cgsize(tcgsize2size[left.location.size]);
  245. if (left.location.size in [OS_32,OS_S32]) then
  246. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara)
  247. else
  248. cg64.a_param64_ref(exprasmlist,left.location.reference,tempcgpara);
  249. end;
  250. {$endif powerpc}
  251. {$if defined(sparc) or defined(arm) }
  252. { sparc and arm pass floats in normal registers }
  253. LOC_REGISTER,
  254. LOC_CREGISTER,
  255. {$endif sparc}
  256. LOC_REFERENCE,
  257. LOC_CREFERENCE,
  258. LOC_FPUREGISTER,
  259. LOC_CFPUREGISTER:
  260. cg.a_paramfpu_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara);
  261. else
  262. internalerror(2002042431);
  263. end;
  264. else
  265. internalerror(2002042432);
  266. end;
  267. {$endif i386}
  268. end
  269. else
  270. begin
  271. case left.location.loc of
  272. LOC_CONSTANT,
  273. LOC_REGISTER,
  274. LOC_CREGISTER,
  275. LOC_REFERENCE,
  276. LOC_CREFERENCE :
  277. begin
  278. {$ifndef cpu64bit}
  279. { use cg64 only for int64, not for 8 byte records }
  280. if is_64bit(left.resulttype.def) then
  281. cg64.a_param64_loc(exprasmlist,left.location,tempcgpara)
  282. else
  283. {$endif cpu64bit}
  284. begin
  285. {$ifndef cpu64bit}
  286. { Only a_param_ref supports multiple locations, when the
  287. value is still a const or in a register then write it
  288. to a reference first. This situation can be triggered
  289. by typecasting an int64 constant to a record of 8 bytes }
  290. if left.location.size in [OS_64,OS_S64] then
  291. location_force_mem(exprasmlist,left.location);
  292. {$endif cpu64bit}
  293. cg.a_param_loc(exprasmlist,left.location,tempcgpara);
  294. end;
  295. end;
  296. {$ifdef SUPPORT_MMX}
  297. LOC_MMXREGISTER,
  298. LOC_CMMXREGISTER:
  299. cg.a_parammm_reg(exprasmlist,OS_M64,left.location.register,tempcgpara,nil);
  300. {$endif SUPPORT_MMX}
  301. else
  302. internalerror(200204241);
  303. end;
  304. end;
  305. end;
  306. procedure tcgcallparanode.secondcallparan;
  307. var
  308. href : treference;
  309. otlabel,
  310. oflabel : tasmlabel;
  311. begin
  312. if not(assigned(parasym)) then
  313. internalerror(200304242);
  314. { Skip nothingn nodes which are used after disabling
  315. a parameter }
  316. if (left.nodetype<>nothingn) then
  317. begin
  318. otlabel:=truelabel;
  319. oflabel:=falselabel;
  320. objectlibrary.getjumplabel(truelabel);
  321. objectlibrary.getjumplabel(falselabel);
  322. secondpass(left);
  323. { release memory for refcnt out parameters }
  324. if (parasym.varspez=vs_out) and
  325. (left.resulttype.def.needs_inittable) then
  326. begin
  327. location_get_data_ref(exprasmlist,left.location,href,false);
  328. cg.g_decrrefcount(exprasmlist,left.resulttype.def,href);
  329. end;
  330. paramanager.createtempparaloc(exprasmlist,aktcallnode.procdefinition.proccalloption,parasym,tempcgpara);
  331. { handle varargs first, because parasym is not valid }
  332. if (cpf_varargs_para in callparaflags) then
  333. begin
  334. if paramanager.push_addr_param(vs_value,left.resulttype.def,
  335. aktcallnode.procdefinition.proccalloption) then
  336. push_addr_para
  337. else
  338. push_value_para;
  339. end
  340. { hidden parameters }
  341. else if (vo_is_hidden_para in parasym.varoptions) then
  342. begin
  343. { don't push a node that already generated a pointer type
  344. by address for implicit hidden parameters }
  345. if (vo_is_funcret in parasym.varoptions) or
  346. (not(left.resulttype.def.deftype in [pointerdef,classrefdef]) and
  347. paramanager.push_addr_param(parasym.varspez,parasym.vartype.def,
  348. aktcallnode.procdefinition.proccalloption)) then
  349. push_addr_para
  350. else
  351. push_value_para;
  352. end
  353. { formal def }
  354. else if (parasym.vartype.def.deftype=formaldef) then
  355. begin
  356. { allow passing of a constant to a const formaldef }
  357. if (parasym.varspez=vs_const) and
  358. (left.location.loc=LOC_CONSTANT) then
  359. location_force_mem(exprasmlist,left.location);
  360. push_addr_para;
  361. end
  362. { Normal parameter }
  363. else
  364. begin
  365. { don't push a node that already generated a pointer type
  366. by address for implicit hidden parameters }
  367. if (not(
  368. (vo_is_hidden_para in parasym.varoptions) and
  369. (left.resulttype.def.deftype in [pointerdef,classrefdef])
  370. ) and
  371. paramanager.push_addr_param(parasym.varspez,parasym.vartype.def,
  372. aktcallnode.procdefinition.proccalloption)) and
  373. { dyn. arrays passed to an array of const must be passed by value, see tests/webtbs/tw4219.pp }
  374. not(
  375. is_array_of_const(parasym.vartype.def) and
  376. is_dynamic_array(left.resulttype.def)
  377. ) then
  378. begin
  379. { Passing a var parameter to a var parameter, we can
  380. just push the address transparently }
  381. if (left.nodetype=loadn) and
  382. (tloadnode(left).is_addr_param_load) then
  383. begin
  384. if (left.location.reference.index<>NR_NO) or
  385. (left.location.reference.offset<>0) then
  386. internalerror(200410107);
  387. cg.a_param_reg(exprasmlist,OS_ADDR,left.location.reference.base,tempcgpara)
  388. end
  389. else
  390. begin
  391. { Check for passing a constant to var,out parameter }
  392. if (parasym.varspez in [vs_var,vs_out]) and
  393. (left.location.loc<>LOC_REFERENCE) then
  394. begin
  395. { passing self to a var parameter is allowed in
  396. TP and delphi }
  397. if not((left.location.loc=LOC_CREFERENCE) and
  398. is_self_node(left)) then
  399. internalerror(200106041);
  400. end;
  401. { Force to be in memory }
  402. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  403. location_force_mem(exprasmlist,left.location);
  404. push_addr_para;
  405. end;
  406. end
  407. else
  408. push_value_para;
  409. end;
  410. truelabel:=otlabel;
  411. falselabel:=oflabel;
  412. { update return location in callnode when this is the function
  413. result }
  414. if assigned(parasym) and
  415. (vo_is_funcret in parasym.varoptions) then
  416. location_copy(aktcallnode.location,left.location);
  417. end;
  418. { next parameter }
  419. if assigned(right) then
  420. tcallparanode(right).secondcallparan;
  421. end;
  422. {*****************************************************************************
  423. TCGCALLNODE
  424. *****************************************************************************}
  425. procedure tcgcallnode.extra_interrupt_code;
  426. begin
  427. end;
  428. procedure tcgcallnode.extra_call_code;
  429. begin
  430. end;
  431. procedure tcgcallnode.extra_post_call_code;
  432. begin
  433. end;
  434. procedure tcgcallnode.pop_parasize(pop_size:longint);
  435. begin
  436. end;
  437. procedure tcgcallnode.handle_return_value;
  438. var
  439. cgsize : tcgsize;
  440. retloc : tlocation;
  441. hregister : tregister;
  442. tempnode : tnode;
  443. begin
  444. cgsize:=procdefinition.funcretloc[callerside].size;
  445. { structured results are easy to handle....
  446. needed also when result_no_used !! }
  447. if (procdefinition.proctypeoption<>potype_constructor) and
  448. paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  449. begin
  450. { Location should be setup by the funcret para }
  451. if location.loc<>LOC_REFERENCE then
  452. internalerror(200304241);
  453. end
  454. else
  455. { ansi/widestrings must be registered, so we can dispose them }
  456. if resulttype.def.needs_inittable then
  457. begin
  458. if procdefinition.funcretloc[callerside].loc<>LOC_REGISTER then
  459. internalerror(200409261);
  460. { the FUNCTION_RESULT_REG is already allocated }
  461. if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
  462. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  463. if not assigned(funcretnode) then
  464. begin
  465. { reg_ref could generate two instrcutions and allocate a register so we've to
  466. save the result first before releasing it }
  467. hregister:=cg.getaddressregister(exprasmlist);
  468. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,procdefinition.funcretloc[callerside].register,hregister);
  469. location_reset(location,LOC_REFERENCE,OS_ADDR);
  470. location.reference:=refcountedtemp;
  471. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,location.reference);
  472. end
  473. else
  474. begin
  475. hregister := cg.getaddressregister(exprasmlist);
  476. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,procdefinition.funcretloc[callerside].register,hregister);
  477. { in case of a regular funcretnode with ret_in_param, the }
  478. { original funcretnode isn't touched -> make sure it's }
  479. { the same here (not sure if it's necessary) }
  480. tempnode := funcretnode.getcopy;
  481. tempnode.pass_2;
  482. location := tempnode.location;
  483. tempnode.free;
  484. cg.g_decrrefcount(exprasmlist,resulttype.def,location.reference);
  485. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,location.reference);
  486. end;
  487. end
  488. else
  489. { normal (ordinal,float,pointer) result value }
  490. begin
  491. { we have only to handle the result if it is used }
  492. if (cnf_return_value_used in callnodeflags) then
  493. begin
  494. location.loc:=procdefinition.funcretloc[callerside].loc;
  495. case procdefinition.funcretloc[callerside].loc of
  496. LOC_FPUREGISTER:
  497. begin
  498. location_reset(location,LOC_FPUREGISTER,cgsize);
  499. location.register:=procdefinition.funcretloc[callerside].register;
  500. {$ifdef x86}
  501. tcgx86(cg).inc_fpu_stack;
  502. {$else x86}
  503. if getsupreg(procdefinition.funcretloc[callerside].register)<first_fpu_imreg then
  504. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  505. hregister:=cg.getfpuregister(exprasmlist,location.size);
  506. cg.a_loadfpu_reg_reg(exprasmlist,location.size,location.register,hregister);
  507. location.register:=hregister;
  508. {$endif x86}
  509. end;
  510. LOC_REGISTER:
  511. begin
  512. if cgsize<>OS_NO then
  513. begin
  514. location_reset(location,LOC_REGISTER,cgsize);
  515. {$ifndef cpu64bit}
  516. if cgsize in [OS_64,OS_S64] then
  517. begin
  518. retloc:=procdefinition.funcretloc[callerside];
  519. if retloc.loc<>LOC_REGISTER then
  520. internalerror(200409141);
  521. { the function result registers are already allocated }
  522. if getsupreg(retloc.register64.reglo)<first_int_imreg then
  523. cg.ungetcpuregister(exprasmlist,retloc.register64.reglo);
  524. location.register64.reglo:=cg.getintregister(exprasmlist,OS_32);
  525. cg.a_load_reg_reg(exprasmlist,OS_32,OS_32,retloc.register64.reglo,location.register64.reglo);
  526. if getsupreg(retloc.register64.reghi)<first_int_imreg then
  527. cg.ungetcpuregister(exprasmlist,retloc.register64.reghi);
  528. location.register64.reghi:=cg.getintregister(exprasmlist,OS_32);
  529. cg.a_load_reg_reg(exprasmlist,OS_32,OS_32,retloc.register64.reghi,location.register64.reghi);
  530. end
  531. else
  532. {$endif cpu64bit}
  533. begin
  534. { change register size after the unget because the
  535. getregister was done for the full register
  536. def_cgsize(resulttype.def) is used here because
  537. it could be a constructor call }
  538. if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
  539. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  540. location.register:=cg.getintregister(exprasmlist,def_cgsize(resulttype.def));
  541. cg.a_load_reg_reg(exprasmlist,cgsize,def_cgsize(resulttype.def),procdefinition.funcretloc[callerside].register,location.register);
  542. end;
  543. end
  544. else
  545. begin
  546. if resulttype.def.size>0 then
  547. internalerror(200305131);
  548. end;
  549. end;
  550. LOC_MMREGISTER:
  551. begin
  552. location_reset(location,LOC_MMREGISTER,cgsize);
  553. if getsupreg(procdefinition.funcretloc[callerside].register)<first_mm_imreg then
  554. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  555. location.register:=cg.getmmregister(exprasmlist,cgsize);
  556. cg.a_loadmm_reg_reg(exprasmlist,cgsize,cgsize,procdefinition.funcretloc[callerside].register,location.register,mms_movescalar);
  557. end;
  558. else
  559. internalerror(200405023);
  560. end;
  561. end
  562. else
  563. begin
  564. {$ifdef x86}
  565. { release FPU stack }
  566. if procdefinition.funcretloc[callerside].loc=LOC_FPUREGISTER then
  567. emit_reg(A_FSTP,S_NO,NR_FPU_RESULT_REG);
  568. {$endif x86}
  569. if cgsize<>OS_NO then
  570. location_free(exprasmlist,procdefinition.funcretloc[callerside]);
  571. location_reset(location,LOC_VOID,OS_NO);
  572. end;
  573. end;
  574. { When the result is not used we need to finalize the result and
  575. can release the temp }
  576. if not(cnf_return_value_used in callnodeflags) then
  577. begin
  578. if location.loc=LOC_REFERENCE then
  579. begin
  580. if resulttype.def.needs_inittable then
  581. cg.g_finalize(exprasmlist,resulttype.def,location.reference);
  582. tg.ungetiftemp(exprasmlist,location.reference)
  583. end;
  584. end;
  585. end;
  586. procedure tcgcallnode.release_para_temps;
  587. var
  588. hp : tnode;
  589. ppn : tcallparanode;
  590. begin
  591. { Release temps from parameters }
  592. ppn:=tcallparanode(left);
  593. while assigned(ppn) do
  594. begin
  595. if assigned(ppn.left) then
  596. begin
  597. { don't release the funcret temp }
  598. if not(assigned(ppn.parasym)) or
  599. not(vo_is_funcret in ppn.parasym.varoptions) then
  600. location_freetemp(exprasmlist,ppn.left.location);
  601. { process also all nodes of an array of const }
  602. hp:=ppn.left;
  603. while (hp.nodetype=typeconvn) do
  604. hp:=ttypeconvnode(hp).left;
  605. if (hp.nodetype=arrayconstructorn) and
  606. assigned(tarrayconstructornode(hp).left) then
  607. begin
  608. while assigned(hp) do
  609. begin
  610. location_freetemp(exprasmlist,tarrayconstructornode(hp).left.location);
  611. hp:=tarrayconstructornode(hp).right;
  612. end;
  613. end;
  614. end;
  615. ppn:=tcallparanode(ppn.right);
  616. end;
  617. end;
  618. procedure tcgcallnode.pushparas;
  619. var
  620. ppn : tcgcallparanode;
  621. callerparaloc,
  622. tmpparaloc : pcgparalocation;
  623. sizeleft: aint;
  624. {$ifdef cputargethasfixedstack}
  625. htempref,
  626. href : treference;
  627. {$endif cputargethasfixedstack}
  628. begin
  629. { copy all resources to the allocated registers }
  630. ppn:=tcgcallparanode(left);
  631. while assigned(ppn) do
  632. begin
  633. if (ppn.left.nodetype<>nothingn) then
  634. begin
  635. { better check for the real location of the parameter here, when stack passed parameters
  636. are saved temporary in registers, checking for the tmpparaloc.loc is wrong
  637. }
  638. paramanager.freeparaloc(exprasmlist,ppn.tempcgpara);
  639. tmpparaloc:=ppn.tempcgpara.location;
  640. sizeleft:=ppn.tempcgpara.intsize;
  641. callerparaloc:=ppn.parasym.paraloc[callerside].location;
  642. while assigned(callerparaloc) do
  643. begin
  644. { Every paraloc must have a matching tmpparaloc }
  645. if not assigned(tmpparaloc) then
  646. internalerror(200408224);
  647. if callerparaloc^.size<>tmpparaloc^.size then
  648. internalerror(200408225);
  649. case callerparaloc^.loc of
  650. LOC_REGISTER:
  651. begin
  652. if tmpparaloc^.loc<>LOC_REGISTER then
  653. internalerror(200408221);
  654. if getsupreg(callerparaloc^.register)<first_int_imreg then
  655. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  656. cg.a_load_reg_reg(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,
  657. tmpparaloc^.register,callerparaloc^.register);
  658. end;
  659. LOC_FPUREGISTER:
  660. begin
  661. if tmpparaloc^.loc<>LOC_FPUREGISTER then
  662. internalerror(200408222);
  663. if getsupreg(callerparaloc^.register)<first_fpu_imreg then
  664. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  665. cg.a_loadfpu_reg_reg(exprasmlist,ppn.tempcgpara.size,tmpparaloc^.register,callerparaloc^.register);
  666. end;
  667. LOC_MMREGISTER:
  668. begin
  669. if tmpparaloc^.loc<>LOC_MMREGISTER then
  670. internalerror(200408223);
  671. if getsupreg(callerparaloc^.register)<first_mm_imreg then
  672. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  673. cg.a_loadmm_reg_reg(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,
  674. tmpparaloc^.register,callerparaloc^.register,mms_movescalar);
  675. end;
  676. LOC_REFERENCE:
  677. begin
  678. {$ifdef cputargethasfixedstack}
  679. { Can't have a data copied to the stack, every location
  680. must contain a valid size field }
  681. if (ppn.tempcgpara.size=OS_NO) and
  682. ((tmpparaloc^.loc<>LOC_REFERENCE) or
  683. assigned(tmpparaloc^.next)) then
  684. internalerror(200501281);
  685. reference_reset_base(href,callerparaloc^.reference.index,callerparaloc^.reference.offset);
  686. { copy parameters in case they were moved to a temp. location because we've a fixed stack }
  687. case tmpparaloc^.loc of
  688. LOC_REFERENCE:
  689. begin
  690. reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset);
  691. { use concatcopy, because it can also be a float which fails when
  692. load_ref_ref is used }
  693. if (ppn.tempcgpara.size <> OS_NO) then
  694. cg.g_concatcopy(exprasmlist,htempref,href,tcgsize2size[tmpparaloc^.size])
  695. else
  696. cg.g_concatcopy(exprasmlist,htempref,href,sizeleft)
  697. end;
  698. LOC_REGISTER:
  699. cg.a_load_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  700. LOC_FPUREGISTER:
  701. cg.a_loadfpu_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.register,href);
  702. LOC_MMREGISTER:
  703. cg.a_loadmm_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href,mms_movescalar);
  704. else
  705. internalerror(200402081);
  706. end;
  707. {$endif cputargethasfixedstack}
  708. end;
  709. end;
  710. dec(sizeleft,tcgsize2size[tmpparaloc^.size]);
  711. callerparaloc:=callerparaloc^.next;
  712. tmpparaloc:=tmpparaloc^.next;
  713. end;
  714. end;
  715. ppn:=tcgcallparanode(ppn.right);
  716. end;
  717. end;
  718. procedure tcgcallnode.freeparas;
  719. var
  720. ppn : tcgcallparanode;
  721. begin
  722. { free the resources allocated for the parameters }
  723. ppn:=tcgcallparanode(left);
  724. while assigned(ppn) do
  725. begin
  726. if (ppn.left.nodetype<>nothingn) then
  727. begin
  728. if (ppn.parasym.paraloc[callerside].location^.loc <> LOC_REFERENCE) then
  729. paramanager.freeparaloc(exprasmlist,ppn.parasym.paraloc[callerside]);
  730. end;
  731. ppn:=tcgcallparanode(ppn.right);
  732. end;
  733. end;
  734. procedure tcgcallnode.pass_2;
  735. var
  736. regs_to_save_int,
  737. regs_to_save_fpu,
  738. regs_to_save_mm : Tcpuregisterset;
  739. href : treference;
  740. pop_size : longint;
  741. pvreg,
  742. vmtreg : tregister;
  743. oldaktcallnode : tcallnode;
  744. begin
  745. if not assigned(procdefinition) or
  746. not procdefinition.has_paraloc_info then
  747. internalerror(200305264);
  748. if assigned(methodpointerinit) then
  749. secondpass(methodpointerinit);
  750. if resulttype.def.needs_inittable and
  751. not paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) and
  752. not assigned(funcretnode) then
  753. begin
  754. tg.gettemptyped(exprasmlist,resulttype.def,tt_normal,refcountedtemp);
  755. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  756. end;
  757. regs_to_save_int:=paramanager.get_volatile_registers_int(procdefinition.proccalloption);
  758. regs_to_save_fpu:=paramanager.get_volatile_registers_fpu(procdefinition.proccalloption);
  759. regs_to_save_mm:=paramanager.get_volatile_registers_mm(procdefinition.proccalloption);
  760. { Include Function result registers }
  761. if (not is_void(resulttype.def)) then
  762. begin
  763. case procdefinition.funcretloc[callerside].loc of
  764. LOC_REGISTER,
  765. LOC_CREGISTER:
  766. include(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  767. LOC_FPUREGISTER,
  768. LOC_CFPUREGISTER:
  769. include(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  770. LOC_MMREGISTER,
  771. LOC_CMMREGISTER:
  772. include(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  773. LOC_REFERENCE,
  774. LOC_VOID:
  775. ;
  776. else
  777. internalerror(2004110213);
  778. end;
  779. end;
  780. { Process parameters, register parameters will be loaded
  781. in imaginary registers. The actual load to the correct
  782. register is done just before the call }
  783. oldaktcallnode:=aktcallnode;
  784. aktcallnode:=self;
  785. if assigned(left) then
  786. tcallparanode(left).secondcallparan;
  787. aktcallnode:=oldaktcallnode;
  788. { procedure variable or normal function call ? }
  789. if (right=nil) then
  790. begin
  791. { When methodpointer is typen we don't need (and can't) load
  792. a pointer. We can directly call the correct procdef (PFV) }
  793. if (po_virtualmethod in procdefinition.procoptions) and
  794. assigned(methodpointer) and
  795. (methodpointer.nodetype<>typen) then
  796. begin
  797. { virtual methods require an index }
  798. if tprocdef(procdefinition).extnumber=$ffff then
  799. internalerror(200304021);
  800. secondpass(methodpointer);
  801. { Load VMT from self }
  802. if methodpointer.resulttype.def.deftype=objectdef then
  803. gen_load_vmt_register(exprasmlist,tobjectdef(methodpointer.resulttype.def),methodpointer.location,vmtreg)
  804. else
  805. begin
  806. { Load VMT value in register }
  807. location_force_reg(exprasmlist,methodpointer.location,OS_ADDR,false);
  808. vmtreg:=methodpointer.location.register;
  809. end;
  810. { test validity of VMT }
  811. if not(is_interface(tprocdef(procdefinition)._class)) and
  812. not(is_cppclass(tprocdef(procdefinition)._class)) then
  813. cg.g_maybe_testvmt(exprasmlist,vmtreg,tprocdef(procdefinition)._class);
  814. pvreg:=cg.getintregister(exprasmlist,OS_ADDR);
  815. reference_reset_base(href,vmtreg,
  816. tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber));
  817. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,pvreg);
  818. { Load parameters that are in temporary registers in the
  819. correct parameter register }
  820. if assigned(left) then
  821. begin
  822. pushparas;
  823. { free the resources allocated for the parameters }
  824. freeparas;
  825. end;
  826. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  827. if cg.uses_registers(R_FPUREGISTER) then
  828. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  829. if cg.uses_registers(R_MMREGISTER) then
  830. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  831. { call method }
  832. extra_call_code;
  833. cg.a_call_reg(exprasmlist,pvreg);
  834. extra_post_call_code;
  835. end
  836. else
  837. begin
  838. { Load parameters that are in temporary registers in the
  839. correct parameter register }
  840. if assigned(left) then
  841. begin
  842. pushparas;
  843. { free the resources allocated for the parameters }
  844. freeparas;
  845. end;
  846. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  847. if cg.uses_registers(R_FPUREGISTER) then
  848. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  849. if cg.uses_registers(R_MMREGISTER) then
  850. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  851. if procdefinition.proccalloption=pocall_syscall then
  852. do_syscall
  853. else
  854. begin
  855. { Calling interrupt from the same code requires some
  856. extra code }
  857. if (po_interrupt in procdefinition.procoptions) then
  858. extra_interrupt_code;
  859. extra_call_code;
  860. cg.a_call_name(exprasmlist,tprocdef(procdefinition).mangledname);
  861. extra_post_call_code;
  862. end;
  863. end;
  864. end
  865. else
  866. { now procedure variable case }
  867. begin
  868. secondpass(right);
  869. pvreg:=cg.getintregister(exprasmlist,OS_ADDR);
  870. { Only load OS_ADDR from the reference }
  871. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  872. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,right.location.reference,pvreg)
  873. else
  874. cg.a_load_loc_reg(exprasmlist,OS_ADDR,right.location,pvreg);
  875. location_freetemp(exprasmlist,right.location);
  876. { Load parameters that are in temporary registers in the
  877. correct parameter register }
  878. if assigned(left) then
  879. begin
  880. pushparas;
  881. { free the resources allocated for the parameters }
  882. freeparas;
  883. end;
  884. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  885. if cg.uses_registers(R_FPUREGISTER) then
  886. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  887. if cg.uses_registers(R_MMREGISTER) then
  888. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  889. { Calling interrupt from the same code requires some
  890. extra code }
  891. if (po_interrupt in procdefinition.procoptions) then
  892. extra_interrupt_code;
  893. extra_call_code;
  894. cg.a_call_reg(exprasmlist,pvreg);
  895. extra_post_call_code;
  896. end;
  897. { Need to remove the parameters from the stack? }
  898. if (procdefinition.proccalloption in clearstack_pocalls) then
  899. begin
  900. pop_size:=pushedparasize;
  901. { for Cdecl functions we don't need to pop the funcret when it
  902. was pushed by para }
  903. if paramanager.ret_in_param(procdefinition.rettype.def,procdefinition.proccalloption) then
  904. dec(pop_size,sizeof(aint));
  905. { Remove parameters/alignment from the stack }
  906. pop_parasize(pop_size);
  907. end;
  908. { Release registers, but not the registers that contain the
  909. function result }
  910. if (not is_void(resulttype.def)) then
  911. begin
  912. case procdefinition.funcretloc[callerside].loc of
  913. LOC_REGISTER,
  914. LOC_CREGISTER:
  915. begin
  916. {$ifndef cpu64bit}
  917. if procdefinition.funcretloc[callerside].size in [OS_64,OS_S64] then
  918. begin
  919. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register64.reghi));
  920. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register64.reglo));
  921. end
  922. else
  923. {$endif cpu64bit}
  924. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  925. end;
  926. LOC_FPUREGISTER,
  927. LOC_CFPUREGISTER:
  928. exclude(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  929. LOC_MMREGISTER,
  930. LOC_CMMREGISTER:
  931. exclude(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  932. LOC_REFERENCE,
  933. LOC_VOID:
  934. ;
  935. else
  936. internalerror(2004110214);
  937. end;
  938. end;
  939. if cg.uses_registers(R_MMREGISTER) then
  940. cg.dealloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  941. if cg.uses_registers(R_FPUREGISTER) then
  942. cg.dealloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  943. cg.dealloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  944. { handle function results }
  945. if (not is_void(resulttype.def)) then
  946. handle_return_value
  947. else
  948. location_reset(location,LOC_VOID,OS_NO);
  949. { perhaps i/o check ? }
  950. if (cs_check_io in aktlocalswitches) and
  951. (po_iocheck in procdefinition.procoptions) and
  952. not(po_iocheck in current_procinfo.procdef.procoptions) and
  953. { no IO check for methods and procedure variables }
  954. (right=nil) and
  955. not(po_virtualmethod in procdefinition.procoptions) then
  956. begin
  957. cg.allocallcpuregisters(exprasmlist);
  958. cg.a_call_name(exprasmlist,'FPC_IOCHECK');
  959. cg.deallocallcpuregisters(exprasmlist);
  960. end;
  961. { release temps of paras }
  962. release_para_temps;
  963. if assigned(methodpointerdone) then
  964. secondpass(methodpointerdone);
  965. end;
  966. begin
  967. ccallparanode:=tcgcallparanode;
  968. ccallnode:=tcgcallnode;
  969. end.