2
0

cpupara.pas 31 KB

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