cpupara.pas 31 KB

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