cpupara.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. {
  2. Copyright (c) 2013-2014 by Jonas Maebe, Florian Klaempfl and others
  3. AArch64 specific calling conventions
  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. { AArch64 specific calling conventions are handled by this unit
  18. }
  19. unit cpupara;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. globtype,globals,
  24. aasmtai,aasmdata,
  25. cpuinfo,cpubase,cgbase,cgutils,
  26. symconst,symbase,symtype,symdef,parabase,paramgr;
  27. type
  28. tcpuparamanager = class(tparamanager)
  29. function get_volatile_registers_int(calloption: tproccalloption): tcpuregisterset; override;
  30. function get_volatile_registers_fpu(calloption: tproccalloption): tcpuregisterset; override;
  31. function get_volatile_registers_mm(calloption: tproccalloption): tcpuregisterset; override;
  32. function push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override;
  33. function ret_in_param(def: tdef; pd: tabstractprocdef):boolean;override;
  34. function create_paraloc_info(p: tabstractprocdef; side: tcallercallee):longint;override;
  35. function create_varargs_paraloc_info(p: tabstractprocdef; varargspara: tvarargsparalist):longint;override;
  36. function get_funcretloc(p: tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
  37. function param_use_paraloc(const cgpara: tcgpara): boolean; override;
  38. private
  39. curintreg,
  40. curmmreg: tsuperregister;
  41. curstackoffset: aword;
  42. procedure init_para_alloc_values;
  43. procedure alloc_para(out result: tcgpara; p: tabstractprocdef; varspez: tvarspez; side: tcallercallee; paradef: tdef; isvariadic, isdelphinestedcc: boolean);
  44. procedure create_paraloc_info_intern(p: tabstractprocdef; side: tcallercallee; paras: tparalist; isvariadic: boolean);
  45. end;
  46. implementation
  47. uses
  48. verbose,systems,cutils,
  49. rgobj,
  50. defutil,symsym,symtable;
  51. const
  52. RS_FIRST_INT_PARAM_SUPREG = RS_X0;
  53. RS_LAST_INT_PARAM_SUPREG = RS_X7;
  54. { Q0/D0/S0/H0/B0 all have the same superregister number }
  55. RS_FIRST_MM_PARAM_SUPREG = RS_D0;
  56. RS_LAST_MM_PARAM_SUPREG = RS_D7;
  57. function tcpuparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  58. begin
  59. result:=VOLATILE_INTREGISTERS
  60. end;
  61. function tcpuparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  62. begin
  63. result:=[];
  64. end;
  65. function tcpuparamanager.get_volatile_registers_mm(calloption: tproccalloption): tcpuregisterset;
  66. begin
  67. result:=VOLATILE_MMREGISTERS;
  68. end;
  69. function is_hfa_internal(p: tdef; var basedef: tdef; var elecount: longint): boolean;
  70. var
  71. i: longint;
  72. sym: tsym;
  73. tmpelecount: longint;
  74. begin
  75. result:=false;
  76. case p.typ of
  77. arraydef:
  78. begin
  79. if is_special_array(p) then
  80. exit;
  81. { an array of empty records has no influence }
  82. if tarraydef(p).elementdef.size=0 then
  83. begin
  84. result:=true;
  85. exit
  86. end;
  87. tmpelecount:=0;
  88. if not is_hfa_internal(tarraydef(p).elementdef,basedef,tmpelecount) then
  89. exit;
  90. { tmpelecount now contains the number of hfa elements in a
  91. single array element (e.g. 2 if it's an array of a record
  92. containing two singles) -> multiply by number of elements
  93. in the array }
  94. inc(elecount,tarraydef(p).elecount*tmpelecount);
  95. if elecount>4 then
  96. exit;
  97. result:=true;
  98. end;
  99. floatdef:
  100. begin
  101. if not assigned(basedef) then
  102. basedef:=p
  103. else if basedef<>p then
  104. exit;
  105. inc(elecount);
  106. result:=true;
  107. end;
  108. recorddef:
  109. begin
  110. for i:=0 to tabstractrecorddef(p).symtable.symlist.count-1 do
  111. begin
  112. sym:=tsym(tabstractrecorddef(p).symtable.symlist[i]);
  113. if sym.typ<>fieldvarsym then
  114. continue;
  115. if not is_hfa_internal(tfieldvarsym(sym).vardef,basedef,elecount) then
  116. exit
  117. end;
  118. result:=true;
  119. end;
  120. else
  121. exit
  122. end;
  123. end;
  124. { Returns whether a def is a "homogeneous float array" at the machine level.
  125. This means that in the memory layout, the def only consists of maximally
  126. 4 floating point values that appear consecutively in memory }
  127. function is_hfa(p: tdef; out basedef: tdef) : boolean;
  128. var
  129. elecount: longint;
  130. begin
  131. result:=false;
  132. basedef:=nil;
  133. elecount:=0;
  134. result:=is_hfa_internal(p,basedef,elecount);
  135. result:=
  136. result and
  137. (elecount>0) and
  138. (elecount<=4) and
  139. (p.size=basedef.size*elecount)
  140. end;
  141. function getparaloc(calloption: tproccalloption; p: tdef): tcgloc;
  142. var
  143. hfabasedef: tdef;
  144. begin
  145. { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
  146. if push_addr_param for the def is true
  147. }
  148. case p.typ of
  149. orddef:
  150. getparaloc:=LOC_REGISTER;
  151. floatdef:
  152. getparaloc:=LOC_MMREGISTER;
  153. enumdef:
  154. getparaloc:=LOC_REGISTER;
  155. pointerdef:
  156. getparaloc:=LOC_REGISTER;
  157. formaldef:
  158. getparaloc:=LOC_REGISTER;
  159. classrefdef:
  160. getparaloc:=LOC_REGISTER;
  161. recorddef:
  162. if not is_hfa(p,hfabasedef) then
  163. getparaloc:=LOC_REGISTER
  164. else
  165. getparaloc:=LOC_MMREGISTER;
  166. objectdef:
  167. getparaloc:=LOC_REGISTER;
  168. stringdef:
  169. if is_shortstring(p) or is_longstring(p) then
  170. getparaloc:=LOC_REFERENCE
  171. else
  172. getparaloc:=LOC_REGISTER;
  173. procvardef:
  174. getparaloc:=LOC_REGISTER;
  175. filedef:
  176. getparaloc:=LOC_REGISTER;
  177. arraydef:
  178. if not is_hfa(p,hfabasedef) then
  179. getparaloc:=LOC_REGISTER
  180. else
  181. getparaloc:=LOC_MMREGISTER;
  182. setdef:
  183. getparaloc:=LOC_REGISTER;
  184. variantdef:
  185. getparaloc:=LOC_REGISTER;
  186. { avoid problems with errornous definitions }
  187. errordef:
  188. getparaloc:=LOC_REGISTER;
  189. else
  190. internalerror(2002071001);
  191. end;
  192. end;
  193. function tcpuparamanager.push_addr_param(varspez: tvarspez; def :tdef; calloption: tproccalloption): boolean;
  194. var
  195. hfabasedef: tdef;
  196. begin
  197. result:=false;
  198. if varspez in [vs_var,vs_out,vs_constref] then
  199. begin
  200. result:=true;
  201. exit;
  202. end;
  203. case def.typ of
  204. objectdef:
  205. result:=is_object(def);
  206. recorddef:
  207. { ABI: any composite > 16 bytes that not a hfa/hva
  208. Special case: MWPascal, which passes all const parameters by
  209. reference for compatibility reasons
  210. }
  211. result:=
  212. ((varspez=vs_const) and
  213. (calloption=pocall_mwpascal)) or
  214. (not is_hfa(def,hfabasedef) and
  215. (def.size>16));
  216. variantdef,
  217. formaldef:
  218. result:=true;
  219. { arrays are composites and hence treated the same as records by the
  220. ABI (watch out for C, where an array is a pointer)
  221. Also: all other platforms pass const arrays by reference. Do the
  222. same here, because there is too much hacky code out there that
  223. relies on this ("array[0..0] of x" passed as const parameter and
  224. then indexed beyond its bounds) }
  225. arraydef:
  226. result:=
  227. (calloption in cdecl_pocalls) or
  228. is_open_array(def) or
  229. is_array_of_const(def) or
  230. is_array_constructor(def) or
  231. ((tarraydef(def).highrange>=tarraydef(def).lowrange) and
  232. ((varspez=vs_const) or
  233. (not is_hfa(def,hfabasedef) and
  234. (def.size>16))));
  235. setdef :
  236. result:=def.size>16;
  237. stringdef :
  238. result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
  239. end;
  240. end;
  241. function tcpuparamanager.ret_in_param(def: tdef; pd: tabstractprocdef): boolean;
  242. begin
  243. if handle_common_ret_in_param(def,pd,result) then
  244. exit;
  245. { ABI: if the parameter would be passed in registers, it is returned
  246. in those registers; otherwise, it's returned by reference }
  247. result:=push_addr_param(vs_value,def,pd.proccalloption);
  248. end;
  249. procedure tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist; isvariadic: boolean);
  250. var
  251. hp: tparavarsym;
  252. i: longint;
  253. begin
  254. for i:=0 to paras.count-1 do
  255. begin
  256. hp:=tparavarsym(paras[i]);
  257. { hidden function result parameter is passed in X8 (doesn't have to
  258. be valid on return) according to the ABI
  259. -- don't follow the ABI for managed types, because
  260. a) they are passed in registers as parameters, so we should also
  261. return them in a register to be ABI-compliant (which we can't
  262. because the entire compiler is built around the idea that
  263. they are returned by reference, for ref-counting performance
  264. and Delphi-compatibility reasons)
  265. b) there are hacks in the system unit that expect that you can
  266. call
  267. function f: com_interface;
  268. as
  269. procedure p(out o: obj);
  270. That can only work in case we do not use x8 to return them
  271. from the function, but the regular first parameter register.
  272. As the ABI says this behaviour is ok for C++ classes with a
  273. non-trivial copy constructor or destructor, it seems reasonable
  274. for us to do this for managed types as well.}
  275. if (vo_is_funcret in hp.varoptions) and
  276. not is_managed_type(hp.vardef) then
  277. begin
  278. hp.paraloc[side].reset;
  279. hp.paraloc[side].size:=OS_ADDR;
  280. hp.paraloc[side].alignment:=voidpointertype.alignment;
  281. hp.paraloc[side].intsize:=voidpointertype.size;
  282. hp.paraloc[side].def:=cpointerdef.getreusable_no_free(hp.vardef);
  283. with hp.paraloc[side].add_location^ do
  284. begin
  285. size:=OS_ADDR;
  286. def:=hp.paraloc[side].def;
  287. loc:=LOC_REGISTER;
  288. register:=NR_X8;
  289. end
  290. end
  291. else
  292. alloc_para(hp.paraloc[side],p,hp.varspez,side,hp.vardef,isvariadic,
  293. (vo_is_parentfp in hp.varoptions) and
  294. (po_delphi_nested_cc in p.procoptions));
  295. end;
  296. end;
  297. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  298. var
  299. retcgsize: tcgsize;
  300. begin
  301. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  302. exit;
  303. { in this case, it must be returned in registers as if it were passed
  304. as the first parameter }
  305. init_para_alloc_values;
  306. alloc_para(result,p,vs_value,side,result.def,false,false);
  307. { sanity check (LOC_VOID for empty records) }
  308. if not assigned(result.location) or
  309. not(result.location^.loc in [LOC_REGISTER,LOC_MMREGISTER,LOC_VOID]) then
  310. internalerror(2014113001);
  311. end;
  312. function tcpuparamanager.param_use_paraloc(const cgpara: tcgpara): boolean;
  313. begin
  314. { we always set up a stack frame -> we can always access the parameters
  315. this way }
  316. result:=
  317. (cgpara.location^.loc=LOC_REFERENCE) and
  318. not assigned(cgpara.location^.next);
  319. end;
  320. procedure tcpuparamanager.init_para_alloc_values;
  321. begin
  322. curintreg:=RS_FIRST_INT_PARAM_SUPREG;
  323. curmmreg:=RS_FIRST_MM_PARAM_SUPREG;
  324. curstackoffset:=0;
  325. end;
  326. procedure tcpuparamanager.alloc_para(out result: tcgpara; p: tabstractprocdef; varspez: tvarspez; side: tcallercallee; paradef: tdef; isvariadic, isdelphinestedcc: boolean);
  327. var
  328. hfabasedef, locdef: tdef;
  329. paraloc: pcgparalocation;
  330. paralen, stackslotlen: asizeint;
  331. loc: tcgloc;
  332. paracgsize, locsize: tcgsize;
  333. firstparaloc: boolean;
  334. begin
  335. result.reset;
  336. { currently only support C-style array of const,
  337. there should be no location assigned to the vararg array itself }
  338. if (p.proccalloption in cstylearrayofconst) and
  339. is_array_of_const(paradef) then
  340. begin
  341. paraloc:=result.add_location;
  342. { hack: the paraloc must be valid, but is not actually used }
  343. paraloc^.loc:=LOC_REGISTER;
  344. paraloc^.register:=NR_X0;
  345. paraloc^.size:=OS_ADDR;
  346. exit;
  347. end;
  348. if push_addr_param(varspez,paradef,p.proccalloption) then
  349. begin
  350. paradef:=cpointerdef.getreusable_no_free(paradef);
  351. loc:=LOC_REGISTER;
  352. paracgsize:=OS_ADDR;
  353. paralen:=tcgsize2size[OS_ADDR];
  354. end
  355. else
  356. begin
  357. if not is_special_array(paradef) then
  358. paralen:=paradef.size
  359. else
  360. paralen:=tcgsize2size[def_cgsize(paradef)];
  361. loc:=getparaloc(p.proccalloption,paradef);
  362. if (paradef.typ in [objectdef,arraydef,recorddef]) and
  363. not is_special_array(paradef) and
  364. (varspez in [vs_value,vs_const]) then
  365. paracgsize:=int_cgsize(paralen)
  366. else
  367. begin
  368. paracgsize:=def_cgsize(paradef);
  369. { for things like formaldef }
  370. if paracgsize=OS_NO then
  371. begin
  372. paracgsize:=OS_ADDR;
  373. paralen:=tcgsize2size[OS_ADDR];
  374. paradef:=voidpointertype;
  375. end;
  376. end
  377. end;
  378. { get hfa basedef if applicable }
  379. if not is_hfa(paradef,hfabasedef) then
  380. hfabasedef:=nil;
  381. result.size:=paracgsize;
  382. result.alignment:=std_param_align;
  383. result.intsize:=paralen;
  384. result.def:=paradef;
  385. { empty record: skipped (explicitly defined by Apple ABI, undefined
  386. by general ABI; libffi also skips them in all cases) }
  387. if not is_special_array(paradef) and
  388. (paradef.size=0) then
  389. begin
  390. paraloc:=result.add_location;
  391. paraloc^.loc:=LOC_VOID;
  392. paraloc^.def:=paradef;
  393. paraloc^.size:=OS_NO;
  394. exit;
  395. end;
  396. { sufficient registers left? }
  397. case loc of
  398. LOC_REGISTER:
  399. begin
  400. { In case of po_delphi_nested_cc, the parent frame pointer
  401. is always passed on the stack. }
  402. if isdelphinestedcc then
  403. loc:=LOC_REFERENCE
  404. else if curintreg+((paralen-1) shr 3)>RS_LAST_INT_PARAM_SUPREG then
  405. begin
  406. { not enough integer registers left -> no more register
  407. parameters, copy all to stack
  408. }
  409. curintreg:=succ(RS_LAST_INT_PARAM_SUPREG);
  410. loc:=LOC_REFERENCE;
  411. end;
  412. end;
  413. LOC_MMREGISTER:
  414. begin;
  415. { every hfa element must be passed in a separate register }
  416. if (assigned(hfabasedef) and
  417. (curmmreg+((paralen-1) div hfabasedef.size)>RS_LAST_MM_PARAM_SUPREG)) or
  418. (curmmreg+((paralen-1) shr 3)>RS_LAST_MM_PARAM_SUPREG) then
  419. begin
  420. { not enough mm registers left -> no more register
  421. parameters, copy all to stack
  422. }
  423. curmmreg:=succ(RS_LAST_MM_PARAM_SUPREG);
  424. loc:=LOC_REFERENCE;
  425. end;
  426. end;
  427. end;
  428. { allocate registers/stack locations }
  429. firstparaloc:=true;
  430. repeat
  431. paraloc:=result.add_location;
  432. { set paraloc size/def }
  433. if assigned(hfabasedef) then
  434. begin
  435. locsize:=def_cgsize(hfabasedef);
  436. locdef:=hfabasedef;
  437. end
  438. { make sure we don't lose whether or not the type is signed }
  439. else if (loc=LOC_REGISTER) and
  440. (paradef.typ<>orddef) then
  441. begin
  442. locsize:=int_cgsize(paralen);
  443. locdef:=get_paraloc_def(paradef,paralen,firstparaloc);
  444. end
  445. else
  446. begin
  447. locsize:=paracgsize;
  448. locdef:=paradef;
  449. end;
  450. if locsize in [OS_NO,OS_128,OS_S128] then
  451. begin
  452. if paralen>4 then
  453. begin
  454. paraloc^.size:=OS_INT;
  455. paraloc^.def:=u64inttype;
  456. end
  457. else
  458. begin
  459. { for 3-byte records }
  460. paraloc^.size:=OS_32;
  461. paraloc^.def:=u32inttype;
  462. end;
  463. end
  464. else
  465. begin
  466. paraloc^.size:=locsize;
  467. paraloc^.def:=locdef;
  468. end;
  469. { paraloc loc }
  470. paraloc^.loc:=loc;
  471. { assign register/stack address }
  472. case loc of
  473. LOC_REGISTER:
  474. begin
  475. paraloc^.register:=newreg(R_INTREGISTER,curintreg,cgsize2subreg(R_INTREGISTER,paraloc^.size));
  476. inc(curintreg);
  477. dec(paralen,tcgsize2size[paraloc^.size]);
  478. { "The general ABI specifies that it is the callee's
  479. responsibility to sign or zero-extend arguments having fewer
  480. than 32 bits, and that unused bits in a register are
  481. unspecified. In iOS, however, the caller must perform such
  482. extensions, up to 32 bits." }
  483. if (target_info.abi=abi_aarch64_darwin) and
  484. (side=callerside) and
  485. is_ordinal(paradef) and
  486. (paradef.size<4) then
  487. paraloc^.size:=OS_32;
  488. { in case it's a composite, "The argument is passed as though
  489. it had been loaded into the registers from a double-word-
  490. aligned address with an appropriate sequence of LDR
  491. instructions loading consecutive registers from memory" ->
  492. in case of big endian, values in not completely filled
  493. registers must be shifted to the top bits }
  494. if (target_info.endian=endian_big) and
  495. not(paraloc^.size in [OS_64,OS_S64]) and
  496. (paradef.typ in [setdef,recorddef,arraydef,objectdef]) then
  497. paraloc^.shiftval:=-(8-tcgsize2size[paraloc^.size]);
  498. end;
  499. LOC_MMREGISTER:
  500. begin
  501. paraloc^.register:=newreg(R_MMREGISTER,curmmreg,cgsize2subreg(R_MMREGISTER,paraloc^.size));
  502. inc(curmmreg);
  503. dec(paralen,tcgsize2size[paraloc^.size]);
  504. end;
  505. LOC_REFERENCE:
  506. begin
  507. paraloc^.size:=paracgsize;
  508. paraloc^.loc:=LOC_REFERENCE;
  509. { the current stack offset may not be properly aligned in
  510. case we're on Darwin have allocated a non-variadic argument
  511. < 8 bytes previously }
  512. if target_info.abi=abi_aarch64_darwin then
  513. curstackoffset:=align(curstackoffset,paraloc^.def.alignment);
  514. { on Darwin, non-variadic arguments take up their actual size
  515. on the stack; on other platforms, they take up a multiple of
  516. 8 bytes }
  517. if (target_info.abi=abi_aarch64_darwin) and
  518. not isvariadic then
  519. stackslotlen:=paralen
  520. else
  521. stackslotlen:=align(paralen,8);
  522. { from the ABI: if arguments occupy partial stack space, they
  523. have to occupy the lowest significant bits of a register
  524. containing that value which is then stored to memory ->
  525. in case of big endian, skip the alignment bytes (if any) }
  526. if target_info.endian=endian_little then
  527. paraloc^.reference.offset:=curstackoffset
  528. else
  529. paraloc^.reference.offset:=curstackoffset+stackslotlen-paralen;
  530. if side=callerside then
  531. paraloc^.reference.index:=NR_STACK_POINTER_REG
  532. else
  533. begin
  534. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  535. inc(paraloc^.reference.offset,16);
  536. end;
  537. inc(curstackoffset,stackslotlen);
  538. paralen:=0
  539. end;
  540. else
  541. internalerror(2002071002);
  542. end;
  543. firstparaloc:=false;
  544. { <=0 for sign/zero-extended locations }
  545. until paralen<=0;
  546. end;
  547. function tcpuparamanager.create_paraloc_info(p: tabstractprocdef; side: tcallercallee):longint;
  548. begin
  549. init_para_alloc_values;
  550. create_paraloc_info_intern(p,side,p.paras,false);
  551. result:=curstackoffset;
  552. create_funcretloc_info(p,side);
  553. end;
  554. function tcpuparamanager.create_varargs_paraloc_info(p: tabstractprocdef; varargspara: tvarargsparalist):longint;
  555. begin
  556. init_para_alloc_values;
  557. { non-variadic parameters }
  558. create_paraloc_info_intern(p,callerside,p.paras,false);
  559. if p.proccalloption in cstylearrayofconst then
  560. begin
  561. { on Darwin, we cannot use any registers for variadic parameters }
  562. if target_info.abi=abi_aarch64_darwin then
  563. begin
  564. curintreg:=succ(RS_LAST_INT_PARAM_SUPREG);
  565. curmmreg:=succ(RS_LAST_MM_PARAM_SUPREG);
  566. end;
  567. { continue loading the parameters }
  568. create_paraloc_info_intern(p,callerside,varargspara,true);
  569. result:=curstackoffset;
  570. end
  571. else
  572. internalerror(200410231);
  573. end;
  574. begin
  575. paramanager:=tcpuparamanager.create;
  576. end.