cpupara.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. {
  2. Copyright (c) 2002 by Florian Klaempfl
  3. Generates the argument location information for 680x0
  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 cpupara;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. cpubase,
  23. aasmdata,
  24. symconst,symtype,symdef,symsym,
  25. parabase,paramgr,cgbase,cgutils;
  26. type
  27. { Returns the location for the nr-st 32 Bit int parameter
  28. if every parameter before is an 32 Bit int parameter as well
  29. and if the calling conventions for the helper routines of the
  30. rtl are used.
  31. }
  32. tcpuparamanager = class(tparamanager)
  33. function ret_in_param(def:tdef;pd:tabstractprocdef):boolean;override;
  34. function param_use_paraloc(const cgpara:tcgpara):boolean;override;
  35. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  36. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  37. function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
  38. procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);override;
  39. function create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;override;
  40. function parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;override;
  41. function get_volatile_registers_int(calloption:tproccalloption):tcpuregisterset;override;
  42. function get_volatile_registers_address(calloption:tproccalloption):tcpuregisterset;override;
  43. function get_volatile_registers_fpu(calloption:tproccalloption):tcpuregisterset;override;
  44. function get_saved_registers_int(calloption:tproccalloption):tcpuregisterarray;override;
  45. function get_saved_registers_address(calloption:tproccalloption):tcpuregisterarray;override;
  46. function get_saved_registers_fpu(calloption:tproccalloption):tcpuregisterarray;override;
  47. function get_para_align(calloption : tproccalloption):byte;override;
  48. private
  49. function parse_loc_string_to_register(var locreg: tregister; const s : string): boolean;
  50. function create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  51. var cur_stack_offset: aword):longint;
  52. function create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  53. var cur_stack_offset: aword):longint;
  54. end;
  55. implementation
  56. uses
  57. verbose,
  58. globals,
  59. systems,
  60. cpuinfo,
  61. defutil,
  62. cutils,
  63. hlcgobj;
  64. const
  65. intparasupregs : array[0..1] of tsuperregister = (RS_D0,RS_D1);
  66. addrparasupregs : array[0..1] of tsuperregister = (RS_A0,RS_A1);
  67. floatparasupregs : array[0..1] of tsuperregister = (RS_FP0,RS_FP1);
  68. function tcpuparamanager.get_volatile_registers_int(calloption:tproccalloption):tcpuregisterset;
  69. begin
  70. { d0 and d1 are considered volatile }
  71. Result:=VOLATILE_INTREGISTERS;
  72. if (target_info.system in [system_m68k_palmos]) or
  73. ((target_info.system in [system_m68k_atari]) and (calloption in [pocall_syscall])) then
  74. include(result,RS_D2);
  75. end;
  76. function tcpuparamanager.get_volatile_registers_address(calloption:tproccalloption):tcpuregisterset;
  77. begin
  78. { a0 and a1 are considered volatile }
  79. Result:=VOLATILE_ADDRESSREGISTERS;
  80. if (target_info.system in [system_m68k_palmos]) or
  81. ((target_info.system in [system_m68k_atari]) and (calloption in [pocall_syscall])) then
  82. include(result,RS_A2);
  83. end;
  84. function tcpuparamanager.get_volatile_registers_fpu(calloption:tproccalloption):tcpuregisterset;
  85. begin
  86. { fp0 and fp1 are considered volatile }
  87. Result:=VOLATILE_FPUREGISTERS;
  88. end;
  89. function tcpuparamanager.get_saved_registers_int(calloption:tproccalloption):tcpuregisterarray;
  90. const
  91. saved_regs: {$ifndef VER3_0}tcpuregisterarray{$else}array[0..5] of tsuperregister{$endif} = (RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7);
  92. begin
  93. result:=saved_regs;
  94. end;
  95. function tcpuparamanager.get_saved_registers_address(calloption:tproccalloption):tcpuregisterarray;
  96. const
  97. saved_addr_regs: {$ifndef VER3_0}tcpuregisterarray{$else}array[0..4] of tsuperregister{$endif} = (RS_A2,RS_A3,RS_A4,RS_A5,RS_A6);
  98. begin
  99. result:=saved_addr_regs;
  100. end;
  101. function tcpuparamanager.get_saved_registers_fpu(calloption:tproccalloption):tcpuregisterarray;
  102. const
  103. saved_fpu_regs: {$ifndef VER3_0}tcpuregisterarray{$else}array[0..5] of tsuperregister{$endif} = (RS_FP2,RS_FP3,RS_FP4,RS_FP5,RS_FP6,RS_FP7);
  104. begin
  105. result:=saved_fpu_regs;
  106. end;
  107. function tcpuparamanager.get_para_align(calloption : tproccalloption):byte;
  108. begin
  109. result:=target_info.stackalign;
  110. end;
  111. function tcpuparamanager.param_use_paraloc(const cgpara:tcgpara):boolean;
  112. var
  113. paraloc : pcgparalocation;
  114. begin
  115. if not assigned(cgpara.location) then
  116. internalerror(200410102);
  117. result:=true;
  118. { All locations are LOC_REFERENCE }
  119. paraloc:=cgpara.location;
  120. while assigned(paraloc) do
  121. begin
  122. if (paraloc^.loc<>LOC_REFERENCE) then
  123. begin
  124. result:=false;
  125. exit;
  126. end;
  127. paraloc:=paraloc^.next;
  128. end;
  129. end;
  130. { TODO: copied from ppc cg, needs work}
  131. function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  132. begin
  133. result:=false;
  134. { var,out,constref always require address }
  135. if varspez in [vs_var,vs_out,vs_constref] then
  136. begin
  137. result:=true;
  138. exit;
  139. end;
  140. case def.typ of
  141. variantdef,
  142. formaldef :
  143. result:=true;
  144. recorddef:
  145. result:=(calloption in [pocall_register]) and
  146. (varspez in [vs_const]);
  147. arraydef:
  148. result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
  149. is_open_array(def) or
  150. is_array_of_const(def) or
  151. is_array_constructor(def);
  152. objectdef :
  153. result:=is_object(def);
  154. setdef :
  155. result:=not is_smallset(def);
  156. stringdef :
  157. result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
  158. procvardef :
  159. { Handling of methods must match that of records }
  160. result:=false;
  161. else
  162. ;
  163. end;
  164. end;
  165. function tcpuparamanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;
  166. begin
  167. if handle_common_ret_in_param(def,pd,result) then
  168. exit;
  169. case def.typ of
  170. recorddef:
  171. if def.size in [1,2,4] then
  172. begin
  173. result:=false;
  174. exit;
  175. end;
  176. else
  177. ;
  178. end;
  179. result:=inherited ret_in_param(def,pd);
  180. end;
  181. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  182. var
  183. paraloc : pcgparalocation;
  184. retcgsize : tcgsize;
  185. retregtype : tregistertype;
  186. begin
  187. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  188. exit;
  189. { always use the whole 32 bit register when returning values }
  190. if (side=calleeside) and
  191. (result.intsize>0) and
  192. (result.intsize<sizeof(aint)) then
  193. begin
  194. result.def:=sinttype;
  195. result.intsize:=sizeof(aint);
  196. retcgsize:=OS_SINT;
  197. result.size:=retcgsize;
  198. end;
  199. paraloc:=result.add_location;
  200. { Return in FPU register? }
  201. if not (cs_fp_emulation in current_settings.moduleswitches) and
  202. not (current_settings.fputype=fpu_soft) and (result.def.typ=floatdef) then
  203. begin
  204. paraloc^.loc:=LOC_FPUREGISTER;
  205. paraloc^.register:=NR_FPU_RESULT_REG;
  206. paraloc^.size:=retcgsize;
  207. paraloc^.def:=result.def;
  208. end
  209. else
  210. { Return in register }
  211. begin
  212. if retcgsize in [OS_64,OS_S64] then
  213. begin
  214. { low 32bits }
  215. paraloc^.loc:=LOC_REGISTER;
  216. paraloc^.size:=OS_32;
  217. paraloc^.def:=u32inttype;
  218. if side=callerside then
  219. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  220. else
  221. paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
  222. { high 32bits }
  223. paraloc:=result.add_location;
  224. paraloc^.loc:=LOC_REGISTER;
  225. paraloc^.size:=OS_32;
  226. paraloc^.def:=u32inttype;
  227. if side=calleeside then
  228. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  229. else
  230. paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
  231. end
  232. else
  233. begin
  234. paraloc^.loc:=LOC_REGISTER;
  235. paraloc^.size:=retcgsize;
  236. paraloc^.def:=result.def;
  237. { GCC (and SVR4 in general maybe?) requires a pointer result on the A0
  238. register, as well as D0. So we init the result to be A0, then copy
  239. it also to D0 in hlcg.gen_load_loc_function_result. This is not pretty,
  240. but we don't really have an architecture for funcretlocs in two
  241. separate locations.
  242. We also have to figure out a better switch for this, because this is
  243. now compiler and platform specific... (KB) }
  244. if (tabstractprocdef(p).proccalloption in [pocall_syscall,pocall_cdecl,pocall_cppdecl]) and
  245. (target_info.system in [system_m68k_palmos,system_m68k_linux]) and
  246. assigned(result.def) and
  247. (result.def.typ in [stringdef,pointerdef,classrefdef,objectdef,
  248. procvardef,procdef,arraydef,formaldef]) then
  249. retregtype:=R_ADDRESSREGISTER
  250. else
  251. retregtype:=R_INTREGISTER;
  252. if retregtype = R_ADDRESSREGISTER then
  253. begin
  254. if side=callerside then
  255. paraloc^.register:=newreg(R_ADDRESSREGISTER,RS_RETURN_ADDRESS_REG,cgsize2subreg(R_ADDRESSREGISTER,retcgsize))
  256. else
  257. paraloc^.register:=newreg(R_ADDRESSREGISTER,RS_RETURN_ADDRESS_REG,cgsize2subreg(R_ADDRESSREGISTER,retcgsize));
  258. end
  259. else
  260. begin
  261. if side=callerside then
  262. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
  263. else
  264. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  265. end;
  266. end;
  267. end;
  268. end;
  269. function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  270. var
  271. cur_stack_offset: aword;
  272. begin
  273. cur_stack_offset:=0;
  274. case p.proccalloption of
  275. pocall_register :
  276. result:=create_register_paraloc_info(p,side,p.paras,cur_stack_offset);
  277. else
  278. result:=create_stdcall_paraloc_info(p,side,p.paras,cur_stack_offset);
  279. end;
  280. create_funcretloc_info(p,side);
  281. end;
  282. function tcpuparamanager.create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  283. var cur_stack_offset: aword):longint;
  284. var
  285. paraloc : pcgparalocation;
  286. hp : tparavarsym;
  287. paracgsize : tcgsize;
  288. paralen : aint;
  289. paradef : tdef;
  290. i : longint;
  291. firstparaloc : boolean;
  292. paraalign : shortint;
  293. begin
  294. result:=0;
  295. if paras.count=0 then
  296. exit;
  297. paraalign:=get_para_align(p.proccalloption);
  298. for i:=0 to paras.count-1 do
  299. begin
  300. hp:=tparavarsym(paras[i]);
  301. paradef:=hp.vardef;
  302. { syscall for AmigaOS can have already a paraloc set }
  303. if (vo_has_explicit_paraloc in hp.varoptions) then
  304. continue;
  305. hp.paraloc[side].reset;
  306. { currently only support C-style array of const }
  307. if (p.proccalloption in cstylearrayofconst) and
  308. is_array_of_const(paradef) then
  309. begin
  310. paraloc:=hp.paraloc[side].add_location;
  311. { hack: the paraloc must be valid, but is not actually used }
  312. paraloc^.loc:=LOC_REGISTER;
  313. paraloc^.register:=NR_D0;
  314. paraloc^.size:=OS_ADDR;
  315. paraloc^.def:=voidpointertype;
  316. break;
  317. end;
  318. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  319. begin
  320. paradef:=cpointerdef.getreusable_no_free(paradef);
  321. paracgsize := OS_ADDR;
  322. paralen := tcgsize2size[OS_ADDR];
  323. end
  324. else
  325. begin
  326. if not is_special_array(paradef) then
  327. paralen:=paradef.size
  328. else
  329. paralen:=tcgsize2size[def_cgsize(paradef)];
  330. paracgsize:=def_cgsize(paradef);
  331. { for things like formaldef }
  332. if (paracgsize=OS_NO) and (paradef.typ<>recorddef) then
  333. begin
  334. paracgsize:=OS_ADDR;
  335. paralen := tcgsize2size[OS_ADDR];
  336. end;
  337. end;
  338. hp.paraloc[side].alignment:=paraalign;
  339. hp.paraloc[side].size:=paracgsize;
  340. hp.paraloc[side].intsize:=paralen;
  341. hp.paraloc[side].def:=paradef;
  342. if (paralen = 0) then
  343. if (paradef.typ = recorddef) then
  344. begin
  345. paraloc:=hp.paraloc[side].add_location;
  346. paraloc^.loc := LOC_VOID;
  347. end
  348. else
  349. internalerror(200506052);
  350. firstparaloc:=true;
  351. { can become < 0 for e.g. 3-byte records }
  352. while (paralen > 0) do
  353. begin
  354. paraloc:=hp.paraloc[side].add_location;
  355. paraloc^.def:=get_paraloc_def(paradef,paralen,firstparaloc);
  356. if (not (cs_fp_emulation in current_settings.moduleswitches)) and
  357. (paradef.typ=floatdef) then
  358. paraloc^.size:=int_float_cgsize(paralen)
  359. else
  360. paraloc^.size:=int_cgsize(paralen);
  361. { various m68k based C ABIs used in the Unix world use a register to
  362. return a struct by address. we will probably need some kind of a
  363. switch to support these various ABIs when generating cdecl calls (KB) }
  364. if ((vo_is_funcret in hp.varoptions) and
  365. (tabstractprocdef(p).proccalloption in [pocall_cdecl,pocall_cppdecl]) and
  366. (target_info.system in [system_m68k_linux]) and
  367. (tabstractprocdef(p).returndef.typ = recorddef)) then
  368. begin
  369. paraloc^.loc:=LOC_REGISTER;
  370. paraloc^.register:=NR_M68K_STRUCT_RESULT_REG;
  371. paralen:=0;
  372. continue;
  373. end;
  374. paraloc^.loc:=LOC_REFERENCE;
  375. paraloc^.reference.offset:=cur_stack_offset;
  376. if (side = callerside) then
  377. paraloc^.reference.index:=NR_STACK_POINTER_REG
  378. else
  379. begin
  380. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  381. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  382. end;
  383. { M68K is a big-endian target }
  384. if (paralen<paraalign) then
  385. inc(paraloc^.reference.offset,paraalign-paralen);
  386. inc(cur_stack_offset,align(paralen,target_info.stackalign));
  387. paralen := 0;
  388. firstparaloc:=false;
  389. end;
  390. end;
  391. result:=cur_stack_offset;
  392. end;
  393. function tcpuparamanager.create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
  394. var cur_stack_offset: aword): longint;
  395. var
  396. hp : tparavarsym;
  397. paradef : tdef;
  398. paraloc : pcgparalocation;
  399. paracgsize : tcgsize;
  400. i : integer;
  401. l,
  402. paralen,
  403. parareg: longint;
  404. addrparareg: longint;
  405. floatparareg: longint;
  406. varalign : longint;
  407. paraalign : shortint;
  408. pass : byte;
  409. firstparaloc,
  410. pushaddr : boolean;
  411. rt: tregistertype;
  412. begin
  413. result:=0;
  414. if paras.count=0 then
  415. exit;
  416. parareg:=0;
  417. addrparareg:=0;
  418. floatparareg:=0;
  419. paraalign:=get_para_align(p.proccalloption);
  420. { clean up here so we can later detect properly if a parameter has been
  421. assigned or not
  422. }
  423. for i:=0 to paras.count-1 do
  424. tparavarsym(paras[i]).paraloc[side].reset;
  425. { Register parameters are assigned from left to right,
  426. stack parameters from right to left so assign first the
  427. register parameters in a first pass, in the second
  428. pass all unhandled parameters are done }
  429. for pass:=1 to 2 do
  430. begin
  431. if pass=1 then
  432. i:=0
  433. else
  434. i:=paras.count-1;
  435. while true do
  436. begin
  437. hp:=tparavarsym(paras[i]);
  438. paradef:=hp.vardef;
  439. if not(assigned(hp.paraloc[side].location)) then
  440. begin
  441. pushaddr:=push_addr_param(hp.varspez,hp.vardef,p.proccalloption);
  442. if pushaddr then
  443. begin
  444. paralen:=sizeof(aint);
  445. paracgsize:=OS_ADDR;
  446. paradef:=cpointerdef.getreusable_no_free(paradef);
  447. end
  448. else
  449. begin
  450. paralen:=push_size(hp.varspez,hp.vardef,p.proccalloption);
  451. paracgsize:=def_cgsize(hp.vardef);
  452. end;
  453. hp.paraloc[side].size:=paracgsize;
  454. hp.paraloc[side].intsize:=paralen;
  455. hp.paraloc[side].Alignment:=paraalign;
  456. hp.paraloc[side].def:=paradef;
  457. {
  458. In case of po_delphi_nested_cc, the parent frame pointer
  459. is also always passed on the stack.
  460. }
  461. rt:=chlcgobj.def2regtyp(paradef);
  462. if (rt=R_FPUREGISTER) and
  463. (floatparareg<=high(floatparasupregs)) and
  464. (not pushaddr) then
  465. begin
  466. if pass=1 then
  467. begin
  468. paraloc:=hp.paraloc[side].add_location;
  469. paraloc^.size:=paracgsize;
  470. paraloc^.def:=paradef;
  471. paraloc^.loc:=LOC_FPUREGISTER;
  472. paraloc^.register:=newreg(R_FPUREGISTER,floatparasupregs[floatparareg],R_SUBNONE);
  473. inc(floatparareg);
  474. end;
  475. end
  476. else
  477. if (((rt=R_INTREGISTER) and (parareg<=high(intparasupregs))) or
  478. ((rt=R_ADDRESSREGISTER) and (addrparareg<=high(addrparasupregs)))) and
  479. (paralen<=sizeof(aint)) and
  480. (not(hp.vardef.typ in [floatdef,recorddef,arraydef]) or
  481. pushaddr or
  482. is_dynamic_array(hp.vardef)) and
  483. (not(vo_is_parentfp in hp.varoptions) or
  484. not(po_delphi_nested_cc in p.procoptions)) then
  485. begin
  486. if pass=1 then
  487. begin
  488. paraloc:=hp.paraloc[side].add_location;
  489. paraloc^.size:=paracgsize;
  490. paraloc^.def:=paradef;
  491. paraloc^.loc:=LOC_REGISTER;
  492. if (rt=R_ADDRESSREGISTER) and (addrparareg<=high(addrparasupregs)) then
  493. begin
  494. paraloc^.register:=newreg(R_ADDRESSREGISTER,addrparasupregs[addrparareg],R_SUBWHOLE);
  495. inc(addrparareg);
  496. end
  497. else
  498. if (rt=R_INTREGISTER) and (parareg<=high(intparasupregs)) then
  499. begin
  500. paraloc^.register:=newreg(R_INTREGISTER,intparasupregs[parareg],cgsize2subreg(R_INTREGISTER,paracgsize));
  501. inc(parareg);
  502. end
  503. else
  504. internalerror(2016051801);
  505. end;
  506. end
  507. else
  508. if pass=2 then
  509. begin
  510. { Copy to stack? }
  511. if (use_fixed_stack) or
  512. (paracgsize=OS_NO) then
  513. begin
  514. paraloc:=hp.paraloc[side].add_location;
  515. paraloc^.loc:=LOC_REFERENCE;
  516. paraloc^.size:=paracgsize;
  517. paraloc^.def:=paradef;
  518. if side=callerside then
  519. paraloc^.reference.index:=NR_STACK_POINTER_REG
  520. else
  521. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  522. varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
  523. paraloc^.reference.offset:=cur_stack_offset;
  524. if (paralen<paraalign) then
  525. inc(paraloc^.reference.offset,paraalign-paralen);
  526. if side=calleeside then
  527. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  528. cur_stack_offset:=align(cur_stack_offset+paralen,varalign);
  529. end
  530. else
  531. begin
  532. if paralen=0 then
  533. internalerror(200501163);
  534. firstparaloc:=true;
  535. while (paralen>0) do
  536. begin
  537. paraloc:=hp.paraloc[side].add_location;
  538. paraloc^.loc:=LOC_REFERENCE;
  539. { Extended and double need a single location }
  540. if (paracgsize in [OS_F64,OS_F32]) then
  541. begin
  542. paraloc^.size:=paracgsize;
  543. paraloc^.def:=paradef;
  544. l:=paralen;
  545. end
  546. else
  547. begin
  548. { We can allocate at maximum 32 bits per location }
  549. if paralen>sizeof(aint) then
  550. begin
  551. l:=sizeof(aint);
  552. paraloc^.def:=uinttype;
  553. end
  554. else
  555. begin
  556. l:=paralen;
  557. paraloc^.def:=get_paraloc_def(paradef,l,firstparaloc);
  558. end;
  559. paraloc^.size:=int_cgsize(l);
  560. end;
  561. if side=callerside then
  562. paraloc^.reference.index:=NR_STACK_POINTER_REG
  563. else
  564. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  565. varalign:=used_align(size_2_align(l),paraalign,paraalign);
  566. paraloc^.reference.offset:=cur_stack_offset;
  567. { M68K is a big-endian target }
  568. if (paralen<paraalign) then
  569. inc(paraloc^.reference.offset,paraalign-paralen);
  570. if side=calleeside then
  571. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  572. cur_stack_offset:=align(cur_stack_offset+l,varalign);
  573. dec(paralen,l);
  574. firstparaloc:=false;
  575. end;
  576. end;
  577. end;
  578. end;
  579. case pass of
  580. 1:
  581. begin
  582. if i=paras.count-1 then
  583. break;
  584. inc(i);
  585. end;
  586. 2:
  587. begin
  588. if i=0 then
  589. break;
  590. dec(i);
  591. end;
  592. else
  593. ;
  594. end;
  595. end;
  596. end;
  597. result:=cur_stack_offset;
  598. end;
  599. function tcpuparamanager.parse_loc_string_to_register(var locreg: tregister; const s : string): boolean;
  600. begin
  601. locreg:=std_regnum_search(lower(s));
  602. result:=(locreg <> NR_NO) and (locreg <> NR_SP);
  603. end;
  604. function tcpuparamanager.parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;
  605. begin
  606. case target_info.system of
  607. system_m68k_amiga:
  608. result:=parse_loc_string_to_register(p.exp_funcretloc, s);
  609. else
  610. internalerror(2005121801);
  611. end;
  612. end;
  613. procedure tcpuparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);
  614. begin
  615. { Never a need for temps when value is pushed (calls inside parameters
  616. will simply allocate even more stack space for their parameters) }
  617. if not(use_fixed_stack) then
  618. can_use_final_stack_loc:=true;
  619. inherited createtempparaloc(list,calloption,parasym,can_use_final_stack_loc,cgpara);
  620. end;
  621. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;
  622. var
  623. cur_stack_offset: aword;
  624. begin
  625. cur_stack_offset:=0;
  626. result:=create_stdcall_paraloc_info(p,side,p.paras,cur_stack_offset);
  627. if (p.proccalloption in cstylearrayofconst) then
  628. begin
  629. { just continue loading the parameters in the registers }
  630. if assigned(varargspara) then
  631. begin
  632. if side=callerside then
  633. result:=create_stdcall_paraloc_info(p,side,varargspara,cur_stack_offset)
  634. else
  635. internalerror(2019021923);
  636. end;
  637. end
  638. else
  639. internalerror(200410231);
  640. create_funcretloc_info(p,side);
  641. end;
  642. begin
  643. paramanager:=tcpuparamanager.create;
  644. end.