cpupara.pas 30 KB

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