cpupara.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  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_darwin) 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. hp.paraloc[side].def:=paradef;
  338. hp.paraloc[side].size:=OS_NO;
  339. hp.paraloc[side].alignment:=std_param_align;
  340. hp.paraloc[side].intsize:=0;
  341. paraloc:=hp.paraloc[side].add_location;
  342. { hack: the paraloc must be valid, but is not actually used }
  343. paraloc^.loc:=LOC_REGISTER;
  344. paraloc^.register:=NR_R0;
  345. paraloc^.size:=OS_ADDR;
  346. paraloc^.def:=voidpointertype;
  347. break;
  348. end;
  349. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  350. begin
  351. paradef:=cpointerdef.getreusable_no_free(paradef);
  352. loc:=LOC_REGISTER;
  353. paracgsize := OS_ADDR;
  354. paralen := tcgsize2size[OS_ADDR];
  355. end
  356. else
  357. begin
  358. if not is_special_array(paradef) then
  359. paralen := paradef.size
  360. else
  361. paralen := tcgsize2size[def_cgsize(paradef)];
  362. loc := getparaloc(p.proccalloption,paradef,isvariadic);
  363. if (paradef.typ in [objectdef,arraydef,recorddef]) and
  364. not is_special_array(paradef) and
  365. (hp.varspez in [vs_value,vs_const]) then
  366. paracgsize := int_cgsize(paralen)
  367. else
  368. begin
  369. paracgsize:=def_cgsize(paradef);
  370. { for things like formaldef }
  371. if (paracgsize=OS_NO) then
  372. begin
  373. paracgsize:=OS_ADDR;
  374. paralen:=tcgsize2size[OS_ADDR];
  375. paradef:=voidpointertype;
  376. end;
  377. end
  378. end;
  379. hp.paraloc[side].size:=paracgsize;
  380. hp.paraloc[side].Alignment:=std_param_align;
  381. hp.paraloc[side].intsize:=paralen;
  382. hp.paraloc[side].def:=paradef;
  383. firstparaloc:=true;
  384. {$ifdef EXTDEBUG}
  385. if paralen=0 then
  386. internalerror(200410311);
  387. {$endif EXTDEBUG}
  388. while paralen>0 do
  389. begin
  390. paraloc:=hp.paraloc[side].add_location;
  391. if (loc=LOC_REGISTER) and (paracgsize in [OS_F32,OS_F64,OS_F80]) then
  392. case paracgsize of
  393. OS_F32:
  394. begin
  395. paraloc^.size:=OS_32;
  396. paraloc^.def:=u32inttype;
  397. end;
  398. OS_F64:
  399. begin
  400. paraloc^.size:=OS_32;
  401. paraloc^.def:=u32inttype;
  402. end;
  403. else
  404. internalerror(2005082901);
  405. end
  406. else if (paracgsize in [OS_NO,OS_64,OS_S64]) then
  407. begin
  408. paraloc^.size:=OS_32;
  409. paraloc^.def:=u32inttype;
  410. end
  411. else
  412. begin
  413. paraloc^.size:=paracgsize;
  414. paraloc^.def:=get_paraloc_def(paradef,paralen,firstparaloc);
  415. end;
  416. case loc of
  417. LOC_REGISTER:
  418. begin
  419. { align registers for eabi }
  420. if (target_info.abi in [abi_eabi,abi_eabihf]) and
  421. firstparaloc and
  422. (paradef.alignment=8) then
  423. begin
  424. if (nextintreg in [RS_R1,RS_R3]) then
  425. inc(nextintreg)
  426. else if nextintreg>RS_R3 then
  427. stack_offset:=align(stack_offset,8);
  428. end;
  429. { this is not abi compliant
  430. why? (FK) }
  431. if nextintreg<=RS_R3 then
  432. begin
  433. paraloc^.loc:=LOC_REGISTER;
  434. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
  435. inc(nextintreg);
  436. end
  437. else
  438. begin
  439. { LOC_REFERENCE always contains everything that's left }
  440. paraloc^.loc:=LOC_REFERENCE;
  441. paraloc^.size:=int_cgsize(paralen);
  442. paraloc^.def:=carraydef.getreusable_no_free(u8inttype,paralen);
  443. if (side=callerside) then
  444. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  445. paraloc^.reference.offset:=stack_offset;
  446. inc(stack_offset,align(paralen,4));
  447. paralen:=0;
  448. end;
  449. end;
  450. LOC_FPUREGISTER:
  451. begin
  452. if nextfloatreg<=RS_F3 then
  453. begin
  454. paraloc^.loc:=LOC_FPUREGISTER;
  455. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  456. inc(nextfloatreg);
  457. end
  458. else
  459. begin
  460. paraloc^.loc:=LOC_REFERENCE;
  461. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  462. paraloc^.reference.offset:=stack_offset;
  463. case paraloc^.size of
  464. OS_F32:
  465. inc(stack_offset,4);
  466. OS_F64:
  467. inc(stack_offset,8);
  468. OS_F80:
  469. inc(stack_offset,10);
  470. OS_F128:
  471. inc(stack_offset,16);
  472. else
  473. internalerror(200403201);
  474. end;
  475. end;
  476. end;
  477. LOC_MMREGISTER:
  478. begin
  479. if (nextmmreg<=RS_D7) or
  480. ((paraloc^.size = OS_F32) and
  481. (sparesinglereg<>NR_NO)) then
  482. begin
  483. paraloc^.loc:=LOC_MMREGISTER;
  484. case paraloc^.size of
  485. OS_F32:
  486. if sparesinglereg = NR_NO then
  487. begin
  488. paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFS);
  489. sparesinglereg:=newreg(R_MMREGISTER,nextmmreg-RS_S0+RS_S1,R_SUBFS);
  490. inc(nextmmreg);
  491. end
  492. else
  493. begin
  494. paraloc^.register:=sparesinglereg;
  495. sparesinglereg := NR_NO;
  496. end;
  497. OS_F64:
  498. begin
  499. paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFD);
  500. inc(nextmmreg);
  501. end;
  502. else
  503. internalerror(2012031601);
  504. end;
  505. end
  506. else
  507. begin
  508. { once a floating point parameters has been placed
  509. on the stack we must not pass any more in vfp regs
  510. even if there is a single precision register still
  511. free}
  512. sparesinglereg := NR_NO;
  513. { LOC_REFERENCE always contains everything that's left }
  514. paraloc^.loc:=LOC_REFERENCE;
  515. paraloc^.size:=int_cgsize(paralen);
  516. paraloc^.def:=carraydef.getreusable_no_free(u8inttype,paralen);
  517. if (side=callerside) then
  518. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  519. paraloc^.reference.offset:=stack_offset;
  520. inc(stack_offset,align(paralen,4));
  521. paralen:=0;
  522. end;
  523. end;
  524. LOC_REFERENCE:
  525. begin
  526. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  527. begin
  528. paraloc^.size:=OS_ADDR;
  529. paraloc^.def:=cpointerdef.getreusable_no_free(paradef);
  530. assignintreg
  531. end
  532. else
  533. begin
  534. { align stack for eabi }
  535. if (target_info.abi in [abi_eabi,abi_eabihf]) and
  536. firstparaloc and
  537. (paradef.alignment=8) then
  538. stack_offset:=align(stack_offset,8);
  539. paraloc^.size:=paracgsize;
  540. paraloc^.def:=paradef;
  541. paraloc^.loc:=LOC_REFERENCE;
  542. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  543. paraloc^.reference.offset:=stack_offset;
  544. inc(stack_offset,align(paralen,4));
  545. paralen:=0
  546. end;
  547. end;
  548. else
  549. internalerror(2002071002);
  550. end;
  551. if side=calleeside then
  552. begin
  553. if paraloc^.loc=LOC_REFERENCE then
  554. begin
  555. paraloc^.reference.index:=current_procinfo.framepointer;
  556. if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
  557. begin
  558. { on non-Darwin, the framepointer contains the value
  559. of the stack pointer on entry. On Darwin, the
  560. framepointer points to the previously saved
  561. framepointer (which is followed only by the saved
  562. return address -> framepointer + 4 = stack pointer
  563. on entry }
  564. if not(target_info.system in systems_darwin) then
  565. inc(paraloc^.reference.offset,4)
  566. else
  567. inc(paraloc^.reference.offset,8);
  568. end;
  569. end;
  570. end;
  571. dec(paralen,tcgsize2size[paraloc^.size]);
  572. firstparaloc:=false
  573. end;
  574. end;
  575. curintreg:=nextintreg;
  576. curfloatreg:=nextfloatreg;
  577. curmmreg:=nextmmreg;
  578. cur_stack_offset:=stack_offset;
  579. result:=cur_stack_offset;
  580. end;
  581. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  582. var
  583. paraloc : pcgparalocation;
  584. retcgsize : tcgsize;
  585. begin
  586. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  587. exit;
  588. paraloc:=result.add_location;
  589. { Return in FPU register? }
  590. if result.def.typ=floatdef then
  591. begin
  592. if (target_info.abi=abi_eabihf) or (p.proccalloption=pocall_hardfloat) then
  593. begin
  594. paraloc^.loc:=LOC_MMREGISTER;
  595. case retcgsize of
  596. OS_64,
  597. OS_F64:
  598. begin
  599. paraloc^.register:=NR_MM_RESULT_REG;
  600. end;
  601. OS_32,
  602. OS_F32:
  603. begin
  604. paraloc^.register:=NR_S0;
  605. end;
  606. else
  607. internalerror(2012032501);
  608. end;
  609. paraloc^.size:=retcgsize;
  610. paraloc^.def:=result.def;
  611. end
  612. else if (p.proccalloption in [pocall_softfloat]) or
  613. (cs_fp_emulation in current_settings.moduleswitches) or
  614. (current_settings.fputype in [fpu_vfpv2,fpu_vfpv3,fpu_vfpv4,fpu_vfpv3_d16,fpu_fpv4_s16]) then
  615. begin
  616. case retcgsize of
  617. OS_64,
  618. OS_F64:
  619. begin
  620. paraloc^.loc:=LOC_REGISTER;
  621. if target_info.endian = endian_big then
  622. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  623. else
  624. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
  625. paraloc^.size:=OS_32;
  626. paraloc^.def:=u32inttype;
  627. paraloc:=result.add_location;
  628. paraloc^.loc:=LOC_REGISTER;
  629. if target_info.endian = endian_big then
  630. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  631. else
  632. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
  633. paraloc^.size:=OS_32;
  634. paraloc^.def:=u32inttype;
  635. end;
  636. OS_32,
  637. OS_F32:
  638. begin
  639. paraloc^.loc:=LOC_REGISTER;
  640. paraloc^.register:=NR_FUNCTION_RETURN_REG;
  641. paraloc^.size:=OS_32;
  642. paraloc^.def:=u32inttype;
  643. end;
  644. else
  645. internalerror(2005082603);
  646. end;
  647. end
  648. else
  649. begin
  650. paraloc^.loc:=LOC_FPUREGISTER;
  651. paraloc^.register:=NR_FPU_RESULT_REG;
  652. paraloc^.size:=retcgsize;
  653. paraloc^.def:=result.def;
  654. end;
  655. end
  656. { Return in register }
  657. else
  658. begin
  659. if retcgsize in [OS_64,OS_S64] then
  660. begin
  661. paraloc^.loc:=LOC_REGISTER;
  662. if target_info.endian = endian_big then
  663. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  664. else
  665. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
  666. paraloc^.size:=OS_32;
  667. paraloc^.def:=u32inttype;
  668. paraloc:=result.add_location;
  669. paraloc^.loc:=LOC_REGISTER;
  670. if target_info.endian = endian_big then
  671. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  672. else
  673. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
  674. paraloc^.size:=OS_32;
  675. paraloc^.def:=u32inttype;
  676. end
  677. else
  678. begin
  679. paraloc^.loc:=LOC_REGISTER;
  680. paraloc^.register:=NR_FUNCTION_RETURN_REG;
  681. case result.IntSize of
  682. 0:
  683. begin
  684. paraloc^.loc:=LOC_VOID;
  685. paraloc^.register:=NR_NO;
  686. paraloc^.size:=OS_NO;
  687. paraloc^.def:=voidpointertype;
  688. end;
  689. 3:
  690. begin
  691. paraloc^.size:=OS_32;
  692. paraloc^.def:=u32inttype;
  693. end;
  694. else
  695. begin
  696. paraloc^.size:=retcgsize;
  697. paraloc^.def:=result.def;
  698. end;
  699. end;
  700. end;
  701. end;
  702. end;
  703. function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  704. var
  705. cur_stack_offset: aword;
  706. curintreg, curfloatreg, curmmreg: tsuperregister;
  707. sparesinglereg:tregister;
  708. begin
  709. init_values(p,side,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
  710. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,false);
  711. create_funcretloc_info(p,side);
  712. end;
  713. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  714. var
  715. cur_stack_offset: aword;
  716. curintreg, curfloatreg, curmmreg: tsuperregister;
  717. sparesinglereg:tregister;
  718. begin
  719. init_values(p,callerside,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
  720. result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true);
  721. if (p.proccalloption in cstylearrayofconst) then
  722. { just continue loading the parameters in the registers }
  723. result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true)
  724. else
  725. internalerror(200410231);
  726. end;
  727. begin
  728. paramanager:=tcpuparamanager.create;
  729. end.