cpupara.pas 31 KB

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