cpupara.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. {
  2. Copyright (c) 2003 by Florian Klaempfl
  3. ARM 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. { ARM specific calling conventions are handled by this unit
  18. }
  19. unit cpupara;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. globtype,globals,
  24. aasmdata,
  25. cpuinfo,cpubase,cgbase,cgutils,
  26. symconst,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 get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray;override;
  33. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  34. function ret_in_param(def:tdef;pd:tabstractprocdef):boolean;override;
  35. procedure getintparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);override;
  36. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  37. function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
  38. function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
  39. private
  40. procedure init_values(p: tabstractprocdef; side: tcallercallee; var curintreg,
  41. curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword;
  42. var sparesinglereg: tregister);
  43. function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  44. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister; isvariadic: boolean):longint;
  45. procedure paradeftointparaloc(paradef: tdef; paracgsize: tcgsize; out paralocdef: tdef; out paralocsize: tcgsize);
  46. end;
  47. implementation
  48. uses
  49. verbose,systems,cutils,
  50. defutil,symsym,symcpu,symtable,
  51. { PowerPC uses procinfo as well in cpupara, so this should not hurt }
  52. procinfo;
  53. function tcpuparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  54. begin
  55. if (target_info.system<>system_arm_darwin) then
  56. result:=VOLATILE_INTREGISTERS
  57. else
  58. result:=VOLATILE_INTREGISTERS_DARWIN;
  59. end;
  60. function tcpuparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  61. begin
  62. result:=VOLATILE_FPUREGISTERS;
  63. end;
  64. function tcpuparamanager.get_volatile_registers_mm(calloption: tproccalloption): tcpuregisterset;
  65. begin
  66. result:=VOLATILE_MMREGISTERS;
  67. end;
  68. function tcpuparamanager.get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray;
  69. const
  70. saved_regs : array[0..6] of tsuperregister =
  71. (RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10);
  72. begin
  73. result:=saved_regs;
  74. end;
  75. procedure tcpuparamanager.getintparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
  76. var
  77. paraloc : pcgparalocation;
  78. psym : tparavarsym;
  79. pdef : tdef;
  80. begin
  81. if nr<1 then
  82. internalerror(2002070801);
  83. psym:=tparavarsym(pd.paras[nr-1]);
  84. pdef:=psym.vardef;
  85. if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
  86. pdef:=cpointerdef.getreusable_no_free(pdef);
  87. cgpara.reset;
  88. cgpara.size:=def_cgsize(pdef);
  89. cgpara.intsize:=tcgsize2size[cgpara.size];
  90. cgpara.alignment:=std_param_align;
  91. cgpara.def:=pdef;
  92. paraloc:=cgpara.add_location;
  93. with paraloc^ do
  94. begin
  95. def:=pdef;
  96. size:=def_cgsize(pdef);
  97. { the four first parameters are passed into registers }
  98. if nr<=4 then
  99. begin
  100. loc:=LOC_REGISTER;
  101. register:=newreg(R_INTREGISTER,RS_R0+nr-1,R_SUBWHOLE);
  102. end
  103. else
  104. begin
  105. { the other parameters are passed on the stack }
  106. loc:=LOC_REFERENCE;
  107. reference.index:=NR_STACK_POINTER_REG;
  108. reference.offset:=(nr-5)*4;
  109. end;
  110. end;
  111. end;
  112. function getparaloc(calloption : tproccalloption; p : tdef; isvariadic: boolean) : tcgloc;
  113. begin
  114. { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
  115. if push_addr_param for the def is true
  116. }
  117. case p.typ of
  118. orddef:
  119. getparaloc:=LOC_REGISTER;
  120. floatdef:
  121. if ((target_info.abi=abi_eabihf) or (calloption=pocall_hardfloat)) and
  122. (not isvariadic) then
  123. getparaloc:=LOC_MMREGISTER
  124. else if (calloption in cdecl_pocalls) or
  125. (cs_fp_emulation in current_settings.moduleswitches) or
  126. (current_settings.fputype in [fpu_vfpv2,fpu_vfpv3,fpu_vfpv4,fpu_vfpv3_d16,fpu_fpv4_s16]) then
  127. { the ARM eabi also allows passing VFP values via VFP registers,
  128. but Mac OS X doesn't seem to do that and linux only does it if
  129. built with the "-mfloat-abi=hard" option }
  130. getparaloc:=LOC_REGISTER
  131. else
  132. getparaloc:=LOC_FPUREGISTER;
  133. enumdef:
  134. getparaloc:=LOC_REGISTER;
  135. pointerdef:
  136. getparaloc:=LOC_REGISTER;
  137. formaldef:
  138. getparaloc:=LOC_REGISTER;
  139. classrefdef:
  140. getparaloc:=LOC_REGISTER;
  141. recorddef:
  142. getparaloc:=LOC_REGISTER;
  143. objectdef:
  144. getparaloc:=LOC_REGISTER;
  145. stringdef:
  146. if is_shortstring(p) or is_longstring(p) then
  147. getparaloc:=LOC_REFERENCE
  148. else
  149. getparaloc:=LOC_REGISTER;
  150. procvardef:
  151. getparaloc:=LOC_REGISTER;
  152. filedef:
  153. getparaloc:=LOC_REGISTER;
  154. arraydef:
  155. if is_dynamic_array(p) then
  156. getparaloc:=LOC_REGISTER
  157. else
  158. getparaloc:=LOC_REFERENCE;
  159. setdef:
  160. if is_smallset(p) then
  161. getparaloc:=LOC_REGISTER
  162. else
  163. getparaloc:=LOC_REFERENCE;
  164. variantdef:
  165. getparaloc:=LOC_REGISTER;
  166. { avoid problems with errornous definitions }
  167. errordef:
  168. getparaloc:=LOC_REGISTER;
  169. else
  170. internalerror(2002071001);
  171. end;
  172. end;
  173. function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  174. begin
  175. result:=false;
  176. if varspez in [vs_var,vs_out,vs_constref] then
  177. begin
  178. result:=true;
  179. exit;
  180. end;
  181. case def.typ of
  182. objectdef:
  183. result:=is_object(def) and ((varspez=vs_const) or (def.size=0));
  184. recorddef:
  185. { note: should this ever be changed, make sure that const records
  186. are always passed by reference for calloption=pocall_mwpascal }
  187. result:=(varspez=vs_const) or (def.size=0);
  188. variantdef,
  189. formaldef:
  190. result:=true;
  191. arraydef:
  192. result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
  193. is_open_array(def) or
  194. is_array_of_const(def) or
  195. is_array_constructor(def);
  196. setdef :
  197. result:=not is_smallset(def);
  198. stringdef :
  199. result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
  200. end;
  201. end;
  202. function tcpuparamanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;
  203. var
  204. i: longint;
  205. sym: tsym;
  206. begin
  207. if handle_common_ret_in_param(def,pd,result) then
  208. exit;
  209. case def.typ of
  210. recorddef:
  211. begin
  212. result:=def.size>4;
  213. if not result and
  214. (target_info.abi in [abi_default,abi_armeb]) then
  215. begin
  216. { in case of the old ARM abi (APCS), a struct is returned in
  217. a register only if it is simple. And what is a (non-)simple
  218. struct:
  219. "A non-simple type is any non-floating-point type of size
  220. greater than one word (including structures containing only
  221. floating-point fields), and certain single-word structured
  222. types."
  223. (-- ARM APCS documentation)
  224. So only floating point types or more than one word ->
  225. definitely non-simple (more than one word is already
  226. checked above). This includes unions/variant records with
  227. overlaid floating point and integer fields.
  228. Smaller than one word struct types are simple if they are
  229. "integer-like", and:
  230. "A structure is termed integer-like if its size is less than
  231. or equal to one word, and the offset of each of its
  232. addressable subfields is zero."
  233. (-- ARM APCS documentation)
  234. An "addressable subfield" is a field of which you can take
  235. the address, which in practive means any non-bitfield.
  236. In Pascal, there is no way to express the difference that
  237. you can have in C between "char" and "int :8". In this
  238. context, we use the fake distinction that a type defined
  239. inside the record itself (such as "a: 0..255;") indicates
  240. a bitpacked field while a field using a different type
  241. (such as "a: byte;") is not.
  242. }
  243. for i:=0 to trecorddef(def).symtable.SymList.count-1 do
  244. begin
  245. sym:=tsym(trecorddef(def).symtable.SymList[i]);
  246. if sym.typ<>fieldvarsym then
  247. continue;
  248. { bitfield -> ignore }
  249. if (trecordsymtable(trecorddef(def).symtable).usefieldalignment=bit_alignment) and
  250. (tfieldvarsym(sym).vardef.typ in [orddef,enumdef]) and
  251. (tfieldvarsym(sym).vardef.owner.defowner=def) then
  252. continue;
  253. { all other fields must be at offset zero }
  254. if tfieldvarsym(sym).fieldoffset<>0 then
  255. begin
  256. result:=true;
  257. exit;
  258. end;
  259. { floating point field -> also by reference }
  260. if tfieldvarsym(sym).vardef.typ=floatdef then
  261. begin
  262. result:=true;
  263. exit;
  264. end;
  265. end;
  266. end;
  267. end;
  268. procvardef:
  269. if not tprocvardef(def).is_addressonly then
  270. result:=true
  271. else
  272. result:=false
  273. else
  274. result:=inherited ret_in_param(def,pd);
  275. end;
  276. end;
  277. procedure tcpuparamanager.init_values(p : tabstractprocdef; side: tcallercallee;
  278. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister);
  279. begin
  280. curintreg:=RS_R0;
  281. curfloatreg:=RS_F0;
  282. curmmreg:=RS_D0;
  283. if (side=calleeside) and (GenerateThumbCode or (pi_estimatestacksize in current_procinfo.flags)) then
  284. cur_stack_offset:=(p as tcpuprocdef).total_stackframe_size
  285. else
  286. cur_stack_offset:=0;
  287. sparesinglereg := NR_NO;
  288. end;
  289. function tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  290. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister; isvariadic: boolean):longint;
  291. var
  292. nextintreg,nextfloatreg,nextmmreg : tsuperregister;
  293. paradef : tdef;
  294. paraloc : pcgparalocation;
  295. stack_offset : aword;
  296. hp : tparavarsym;
  297. loc : tcgloc;
  298. paracgsize : tcgsize;
  299. paralen : longint;
  300. i : integer;
  301. firstparaloc: boolean;
  302. procedure assignintreg;
  303. begin
  304. { In case of po_delphi_nested_cc, the parent frame pointer
  305. is always passed on the stack. }
  306. if (nextintreg<=RS_R3) and
  307. (not(vo_is_parentfp in hp.varoptions) or
  308. not(po_delphi_nested_cc in p.procoptions)) then
  309. begin
  310. paraloc^.loc:=LOC_REGISTER;
  311. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
  312. inc(nextintreg);
  313. end
  314. else
  315. begin
  316. paraloc^.loc:=LOC_REFERENCE;
  317. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  318. paraloc^.reference.offset:=stack_offset;
  319. inc(stack_offset,4);
  320. end;
  321. end;
  322. begin
  323. result:=0;
  324. nextintreg:=curintreg;
  325. nextfloatreg:=curfloatreg;
  326. nextmmreg:=curmmreg;
  327. stack_offset:=cur_stack_offset;
  328. for i:=0 to paras.count-1 do
  329. begin
  330. hp:=tparavarsym(paras[i]);
  331. paradef:=hp.vardef;
  332. hp.paraloc[side].reset;
  333. { currently only support C-style array of const,
  334. there should be no location assigned to the vararg array itself }
  335. if (p.proccalloption in cstylearrayofconst) and
  336. is_array_of_const(paradef) then
  337. begin
  338. hp.paraloc[side].def:=paradef;
  339. hp.paraloc[side].size:=OS_NO;
  340. hp.paraloc[side].alignment:=std_param_align;
  341. hp.paraloc[side].intsize:=0;
  342. paraloc:=hp.paraloc[side].add_location;
  343. { hack: the paraloc must be valid, but is not actually used }
  344. paraloc^.loc:=LOC_REGISTER;
  345. paraloc^.register:=NR_R0;
  346. paraloc^.size:=OS_ADDR;
  347. paraloc^.def:=voidpointertype;
  348. break;
  349. end;
  350. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  351. begin
  352. paradef:=cpointerdef.getreusable_no_free(paradef);
  353. loc:=LOC_REGISTER;
  354. paracgsize := OS_ADDR;
  355. paralen := tcgsize2size[OS_ADDR];
  356. end
  357. else
  358. begin
  359. if not is_special_array(paradef) then
  360. paralen := paradef.size
  361. else
  362. paralen := tcgsize2size[def_cgsize(paradef)];
  363. loc := getparaloc(p.proccalloption,paradef,isvariadic);
  364. if (paradef.typ in [objectdef,arraydef,recorddef]) and
  365. not is_special_array(paradef) and
  366. (hp.varspez in [vs_value,vs_const]) then
  367. paracgsize := int_cgsize(paralen)
  368. else
  369. begin
  370. paracgsize:=def_cgsize(paradef);
  371. { for things like formaldef }
  372. if (paracgsize=OS_NO) then
  373. begin
  374. paracgsize:=OS_ADDR;
  375. paralen:=tcgsize2size[OS_ADDR];
  376. paradef:=voidpointertype;
  377. end;
  378. end
  379. end;
  380. hp.paraloc[side].size:=paracgsize;
  381. hp.paraloc[side].Alignment:=std_param_align;
  382. hp.paraloc[side].intsize:=paralen;
  383. hp.paraloc[side].def:=paradef;
  384. firstparaloc:=true;
  385. {$ifdef EXTDEBUG}
  386. if paralen=0 then
  387. internalerror(200410311);
  388. {$endif EXTDEBUG}
  389. while paralen>0 do
  390. begin
  391. paraloc:=hp.paraloc[side].add_location;
  392. case loc of
  393. LOC_REGISTER:
  394. begin
  395. if paracgsize in [OS_F32,OS_F64,OS_F80] then
  396. case paracgsize of
  397. OS_F32,
  398. OS_F64:
  399. begin
  400. paraloc^.size:=OS_32;
  401. paraloc^.def:=u32inttype;
  402. end;
  403. else
  404. internalerror(2005082901);
  405. end;
  406. { align registers for eabi }
  407. if (target_info.abi in [abi_eabi,abi_eabihf]) and
  408. firstparaloc and
  409. (paradef.alignment=8) then
  410. begin
  411. if (nextintreg in [RS_R1,RS_R3]) then
  412. inc(nextintreg)
  413. else if nextintreg>RS_R3 then
  414. begin
  415. stack_offset:=align(stack_offset,8);
  416. hp.paraloc[side].Alignment:=8;
  417. end;
  418. end;
  419. if nextintreg<=RS_R3 then
  420. begin
  421. paradeftointparaloc(paradef,paracgsize,paraloc^.def,paraloc^.size);
  422. paraloc^.loc:=LOC_REGISTER;
  423. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
  424. inc(nextintreg);
  425. end
  426. else
  427. begin
  428. { LOC_REFERENCE always contains everything that's left as a multiple of 4 bytes}
  429. paraloc^.loc:=LOC_REFERENCE;
  430. paraloc^.def:=get_paraloc_def(paradef,paralen,firstparaloc);
  431. paraloc^.size:=def_cgsize(paraloc^.def);
  432. if (side=callerside) then
  433. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  434. paraloc^.reference.offset:=stack_offset;
  435. inc(stack_offset,align(paralen,4));
  436. paralen:=0;
  437. end;
  438. end;
  439. LOC_FPUREGISTER:
  440. begin
  441. paraloc^.size:=paracgsize;
  442. paraloc^.def:=paradef;
  443. if nextfloatreg<=RS_F3 then
  444. begin
  445. paraloc^.loc:=LOC_FPUREGISTER;
  446. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  447. inc(nextfloatreg);
  448. end
  449. else
  450. begin
  451. paraloc^.loc:=LOC_REFERENCE;
  452. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  453. paraloc^.reference.offset:=stack_offset;
  454. case paraloc^.size of
  455. OS_F32:
  456. inc(stack_offset,4);
  457. OS_F64:
  458. inc(stack_offset,8);
  459. OS_F80:
  460. inc(stack_offset,10);
  461. OS_F128:
  462. inc(stack_offset,16);
  463. else
  464. internalerror(200403201);
  465. end;
  466. end;
  467. end;
  468. LOC_MMREGISTER:
  469. begin
  470. paraloc^.size:=paracgsize;
  471. paraloc^.def:=paradef;
  472. if (nextmmreg<=RS_D7) or
  473. ((paraloc^.size = OS_F32) and
  474. (sparesinglereg<>NR_NO)) then
  475. begin
  476. paraloc^.loc:=LOC_MMREGISTER;
  477. case paraloc^.size of
  478. OS_F32:
  479. if sparesinglereg = NR_NO then
  480. begin
  481. paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFS);
  482. sparesinglereg:=newreg(R_MMREGISTER,nextmmreg-RS_S0+RS_S1,R_SUBFS);
  483. inc(nextmmreg);
  484. end
  485. else
  486. begin
  487. paraloc^.register:=sparesinglereg;
  488. sparesinglereg := NR_NO;
  489. end;
  490. OS_F64:
  491. begin
  492. paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFD);
  493. inc(nextmmreg);
  494. end;
  495. else
  496. internalerror(2012031601);
  497. end;
  498. end
  499. else
  500. begin
  501. { once a floating point parameters has been placed
  502. on the stack we must not pass any more in vfp regs
  503. even if there is a single precision register still
  504. free}
  505. sparesinglereg := NR_NO;
  506. { LOC_REFERENCE always contains everything that's left }
  507. paraloc^.loc:=LOC_REFERENCE;
  508. paraloc^.size:=int_cgsize(paralen);
  509. if (side=callerside) then
  510. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  511. paraloc^.reference.offset:=stack_offset;
  512. inc(stack_offset,align(paralen,4));
  513. paralen:=0;
  514. end;
  515. end;
  516. LOC_REFERENCE:
  517. begin
  518. paraloc^.size:=paracgsize;
  519. paraloc^.def:=paradef;
  520. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  521. begin
  522. paraloc^.size:=OS_ADDR;
  523. paraloc^.def:=cpointerdef.getreusable_no_free(paradef);
  524. assignintreg
  525. end
  526. else
  527. begin
  528. { align stack for eabi }
  529. if (target_info.abi in [abi_eabi,abi_eabihf]) and
  530. firstparaloc and
  531. (paradef.alignment=8) then
  532. begin
  533. stack_offset:=align(stack_offset,8);
  534. hp.paraloc[side].Alignment:=8;
  535. end;
  536. paraloc^.loc:=LOC_REFERENCE;
  537. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  538. paraloc^.reference.offset:=stack_offset;
  539. inc(stack_offset,align(paralen,4));
  540. paralen:=0
  541. end;
  542. end;
  543. else
  544. internalerror(2002071002);
  545. end;
  546. if side=calleeside then
  547. begin
  548. if paraloc^.loc=LOC_REFERENCE then
  549. begin
  550. paraloc^.reference.index:=current_procinfo.framepointer;
  551. if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
  552. begin
  553. { on non-Darwin, the framepointer contains the value
  554. of the stack pointer on entry. On Darwin, the
  555. framepointer points to the previously saved
  556. framepointer (which is followed only by the saved
  557. return address -> framepointer + 4 = stack pointer
  558. on entry }
  559. if not(target_info.system in systems_darwin) then
  560. inc(paraloc^.reference.offset,4)
  561. else
  562. inc(paraloc^.reference.offset,8);
  563. end;
  564. end;
  565. end;
  566. dec(paralen,tcgsize2size[paraloc^.size]);
  567. firstparaloc:=false
  568. end;
  569. end;
  570. curintreg:=nextintreg;
  571. curfloatreg:=nextfloatreg;
  572. curmmreg:=nextmmreg;
  573. cur_stack_offset:=stack_offset;
  574. result:=cur_stack_offset;
  575. end;
  576. procedure tcpuparamanager.paradeftointparaloc(paradef: tdef; paracgsize: tcgsize; out paralocdef: tdef; out paralocsize: tcgsize);
  577. begin
  578. if not(paracgsize in [OS_32,OS_S32]) or
  579. (paradef.typ in [arraydef,recorddef]) or
  580. is_object(paradef) then
  581. begin
  582. paralocsize:=OS_32;
  583. paralocdef:=u32inttype;
  584. end
  585. else
  586. begin
  587. paralocsize:=paracgsize;
  588. paralocdef:=paradef;
  589. end;
  590. end;
  591. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  592. var
  593. paraloc : pcgparalocation;
  594. retcgsize : tcgsize;
  595. begin
  596. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  597. exit;
  598. paraloc:=result.add_location;
  599. { Return in FPU register? }
  600. if result.def.typ=floatdef then
  601. begin
  602. if (target_info.abi=abi_eabihf) or (p.proccalloption=pocall_hardfloat) then
  603. begin
  604. paraloc^.loc:=LOC_MMREGISTER;
  605. case retcgsize of
  606. OS_64,
  607. OS_F64:
  608. begin
  609. paraloc^.register:=NR_MM_RESULT_REG;
  610. end;
  611. OS_32,
  612. OS_F32:
  613. begin
  614. paraloc^.register:=NR_S0;
  615. end;
  616. else
  617. internalerror(2012032501);
  618. end;
  619. paraloc^.size:=retcgsize;
  620. paraloc^.def:=result.def;
  621. end
  622. else if (p.proccalloption in [pocall_softfloat]) or
  623. (cs_fp_emulation in current_settings.moduleswitches) or
  624. (current_settings.fputype in [fpu_vfpv2,fpu_vfpv3,fpu_vfpv4,fpu_vfpv3_d16,fpu_fpv4_s16]) then
  625. begin
  626. case retcgsize of
  627. OS_64,
  628. OS_F64:
  629. begin
  630. paraloc^.loc:=LOC_REGISTER;
  631. if target_info.endian = endian_big then
  632. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  633. else
  634. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
  635. paraloc^.size:=OS_32;
  636. paraloc^.def:=u32inttype;
  637. paraloc:=result.add_location;
  638. paraloc^.loc:=LOC_REGISTER;
  639. if target_info.endian = endian_big then
  640. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  641. else
  642. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
  643. paraloc^.size:=OS_32;
  644. paraloc^.def:=u32inttype;
  645. end;
  646. OS_32,
  647. OS_F32:
  648. begin
  649. paraloc^.loc:=LOC_REGISTER;
  650. paraloc^.register:=NR_FUNCTION_RETURN_REG;
  651. paraloc^.size:=OS_32;
  652. paraloc^.def:=u32inttype;
  653. end;
  654. else
  655. internalerror(2005082603);
  656. end;
  657. end
  658. else
  659. begin
  660. paraloc^.loc:=LOC_FPUREGISTER;
  661. paraloc^.register:=NR_FPU_RESULT_REG;
  662. paraloc^.size:=retcgsize;
  663. paraloc^.def:=result.def;
  664. end;
  665. end
  666. { Return in register }
  667. else
  668. begin
  669. if retcgsize in [OS_64,OS_S64] then
  670. begin
  671. paraloc^.loc:=LOC_REGISTER;
  672. if target_info.endian = endian_big then
  673. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  674. else
  675. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
  676. paraloc^.size:=OS_32;
  677. paraloc^.def:=u32inttype;
  678. paraloc:=result.add_location;
  679. paraloc^.loc:=LOC_REGISTER;
  680. if target_info.endian = endian_big then
  681. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  682. else
  683. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
  684. paraloc^.size:=OS_32;
  685. paraloc^.def:=u32inttype;
  686. end
  687. else
  688. begin
  689. paraloc^.loc:=LOC_REGISTER;
  690. paraloc^.register:=NR_FUNCTION_RETURN_REG;
  691. case result.IntSize of
  692. 0:
  693. begin
  694. paraloc^.loc:=LOC_VOID;
  695. paraloc^.register:=NR_NO;
  696. paraloc^.size:=OS_NO;
  697. paraloc^.def:=voidpointertype;
  698. end;
  699. 3:
  700. begin
  701. paraloc^.size:=OS_32;
  702. paraloc^.def:=u32inttype;
  703. end;
  704. else
  705. begin
  706. paradeftointparaloc(result.def,result.size,paraloc^.def,paraloc^.size);
  707. end;
  708. end;
  709. end;
  710. end;
  711. end;
  712. function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  713. var
  714. cur_stack_offset: aword;
  715. curintreg, curfloatreg, curmmreg: tsuperregister;
  716. sparesinglereg:tregister;
  717. begin
  718. init_values(p,side,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
  719. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,false);
  720. create_funcretloc_info(p,side);
  721. end;
  722. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  723. var
  724. cur_stack_offset: aword;
  725. curintreg, curfloatreg, curmmreg: tsuperregister;
  726. sparesinglereg:tregister;
  727. begin
  728. init_values(p,callerside,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
  729. result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true);
  730. if (p.proccalloption in cstylearrayofconst) then
  731. { just continue loading the parameters in the registers }
  732. result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true)
  733. else
  734. internalerror(200410231);
  735. end;
  736. begin
  737. paramanager:=tcpuparamanager.create;
  738. end.