cpupara.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  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(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister);
  39. function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  40. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister; isvariadic: boolean):longint;
  41. end;
  42. implementation
  43. uses
  44. verbose,systems,cutils,
  45. defutil,symsym,symtable;
  46. function tarmparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  47. begin
  48. if (target_info.system<>system_arm_darwin) then
  49. result:=VOLATILE_INTREGISTERS
  50. else
  51. result:=VOLATILE_INTREGISTERS_DARWIN;
  52. end;
  53. function tarmparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  54. begin
  55. result:=VOLATILE_FPUREGISTERS;
  56. end;
  57. function tarmparamanager.get_volatile_registers_mm(calloption: tproccalloption): tcpuregisterset;
  58. begin
  59. result:=VOLATILE_MMREGISTERS;
  60. end;
  61. procedure tarmparamanager.getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
  62. var
  63. paraloc : pcgparalocation;
  64. def : tdef;
  65. begin
  66. if nr<1 then
  67. internalerror(2002070801);
  68. def:=tparavarsym(pd.paras[nr-1]).vardef;
  69. cgpara.reset;
  70. cgpara.size:=def_cgsize(def);
  71. cgpara.intsize:=tcgsize2size[cgpara.size];
  72. cgpara.alignment:=std_param_align;
  73. cgpara.def:=def;
  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,fpu_fpv4_s16]) 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;pd:tabstractprocdef):boolean;
  181. var
  182. i: longint;
  183. sym: tsym;
  184. fpufield: boolean;
  185. begin
  186. { this must be system independent safecall and record constructor result
  187. is always return in param }
  188. if (tf_safecall_exceptions in target_info.flags) and
  189. (pd.proccalloption=pocall_safecall) or
  190. ((pd.proctypeoption=potype_constructor)and is_record(def)) then
  191. begin
  192. result:=true;
  193. exit;
  194. end;
  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(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister);
  264. begin
  265. curintreg:=RS_R0;
  266. curfloatreg:=RS_F0;
  267. curmmreg:=RS_D0;
  268. cur_stack_offset:=0;
  269. sparesinglereg := NR_NO;
  270. end;
  271. function tarmparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  272. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister; isvariadic: boolean):longint;
  273. var
  274. nextintreg,nextfloatreg,nextmmreg : tsuperregister;
  275. paradef : tdef;
  276. paraloc : pcgparalocation;
  277. stack_offset : aword;
  278. hp : tparavarsym;
  279. loc : tcgloc;
  280. paracgsize : tcgsize;
  281. paralen : longint;
  282. i : integer;
  283. firstparaloc: boolean;
  284. procedure assignintreg;
  285. begin
  286. { In case of po_delphi_nested_cc, the parent frame pointer
  287. is always passed on the stack. }
  288. if (nextintreg<=RS_R3) and
  289. (not(vo_is_parentfp in hp.varoptions) or
  290. not(po_delphi_nested_cc in p.procoptions)) then
  291. begin
  292. paraloc^.loc:=LOC_REGISTER;
  293. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
  294. inc(nextintreg);
  295. end
  296. else
  297. begin
  298. paraloc^.loc:=LOC_REFERENCE;
  299. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  300. paraloc^.reference.offset:=stack_offset;
  301. inc(stack_offset,4);
  302. end;
  303. end;
  304. begin
  305. result:=0;
  306. nextintreg:=curintreg;
  307. nextfloatreg:=curfloatreg;
  308. nextmmreg:=curmmreg;
  309. stack_offset:=cur_stack_offset;
  310. for i:=0 to paras.count-1 do
  311. begin
  312. hp:=tparavarsym(paras[i]);
  313. paradef:=hp.vardef;
  314. hp.paraloc[side].reset;
  315. { currently only support C-style array of const,
  316. there should be no location assigned to the vararg array itself }
  317. if (p.proccalloption in cstylearrayofconst) and
  318. is_array_of_const(paradef) then
  319. begin
  320. paraloc:=hp.paraloc[side].add_location;
  321. { hack: the paraloc must be valid, but is not actually used }
  322. paraloc^.loc:=LOC_REGISTER;
  323. paraloc^.register:=NR_R0;
  324. paraloc^.size:=OS_ADDR;
  325. break;
  326. end;
  327. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  328. begin
  329. paradef:=getpointerdef(paradef);
  330. loc:=LOC_REGISTER;
  331. paracgsize := OS_ADDR;
  332. paralen := tcgsize2size[OS_ADDR];
  333. end
  334. else
  335. begin
  336. if not is_special_array(paradef) then
  337. paralen := paradef.size
  338. else
  339. paralen := tcgsize2size[def_cgsize(paradef)];
  340. loc := getparaloc(p.proccalloption,paradef,isvariadic);
  341. if (paradef.typ in [objectdef,arraydef,recorddef]) and
  342. not is_special_array(paradef) and
  343. (hp.varspez in [vs_value,vs_const]) then
  344. paracgsize := int_cgsize(paralen)
  345. else
  346. begin
  347. paracgsize:=def_cgsize(paradef);
  348. { for things like formaldef }
  349. if (paracgsize=OS_NO) then
  350. begin
  351. paracgsize:=OS_ADDR;
  352. paralen:=tcgsize2size[OS_ADDR];
  353. paradef:=voidpointertype;
  354. end;
  355. end
  356. end;
  357. hp.paraloc[side].size:=paracgsize;
  358. hp.paraloc[side].Alignment:=std_param_align;
  359. hp.paraloc[side].intsize:=paralen;
  360. hp.paraloc[side].def:=paradef;
  361. firstparaloc:=true;
  362. {$ifdef EXTDEBUG}
  363. if paralen=0 then
  364. internalerror(200410311);
  365. {$endif EXTDEBUG}
  366. while paralen>0 do
  367. begin
  368. paraloc:=hp.paraloc[side].add_location;
  369. if (loc=LOC_REGISTER) and (paracgsize in [OS_F32,OS_F64,OS_F80]) then
  370. case paracgsize of
  371. OS_F32:
  372. paraloc^.size:=OS_32;
  373. OS_F64:
  374. paraloc^.size:=OS_32;
  375. else
  376. internalerror(2005082901);
  377. end
  378. else if (paracgsize in [OS_NO,OS_64,OS_S64]) then
  379. paraloc^.size := OS_32
  380. else
  381. paraloc^.size:=paracgsize;
  382. case loc of
  383. LOC_REGISTER:
  384. begin
  385. { align registers for eabi }
  386. if (target_info.abi in [abi_eabi,abi_eabihf]) and
  387. firstparaloc and
  388. (paradef.alignment=8) then
  389. begin
  390. if (nextintreg in [RS_R1,RS_R3]) then
  391. inc(nextintreg)
  392. else if nextintreg>RS_R3 then
  393. stack_offset:=align(stack_offset,8);
  394. end;
  395. { this is not abi compliant
  396. why? (FK) }
  397. if nextintreg<=RS_R3 then
  398. begin
  399. paraloc^.loc:=LOC_REGISTER;
  400. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
  401. inc(nextintreg);
  402. end
  403. else
  404. begin
  405. { LOC_REFERENCE always contains everything that's left }
  406. paraloc^.loc:=LOC_REFERENCE;
  407. paraloc^.size:=int_cgsize(paralen);
  408. if (side=callerside) then
  409. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  410. paraloc^.reference.offset:=stack_offset;
  411. inc(stack_offset,align(paralen,4));
  412. paralen:=0;
  413. end;
  414. end;
  415. LOC_FPUREGISTER:
  416. begin
  417. if nextfloatreg<=RS_F3 then
  418. begin
  419. paraloc^.loc:=LOC_FPUREGISTER;
  420. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  421. inc(nextfloatreg);
  422. end
  423. else
  424. begin
  425. paraloc^.loc:=LOC_REFERENCE;
  426. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  427. paraloc^.reference.offset:=stack_offset;
  428. case paraloc^.size of
  429. OS_F32:
  430. inc(stack_offset,4);
  431. OS_F64:
  432. inc(stack_offset,8);
  433. OS_F80:
  434. inc(stack_offset,10);
  435. OS_F128:
  436. inc(stack_offset,16);
  437. else
  438. internalerror(200403201);
  439. end;
  440. end;
  441. end;
  442. LOC_MMREGISTER:
  443. begin
  444. if (nextmmreg<=RS_D7) or
  445. ((paraloc^.size = OS_F32) and
  446. (sparesinglereg<>NR_NO)) then
  447. begin
  448. paraloc^.loc:=LOC_MMREGISTER;
  449. case paraloc^.size of
  450. OS_F32:
  451. if sparesinglereg = NR_NO then
  452. begin
  453. paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFS);
  454. sparesinglereg:=newreg(R_MMREGISTER,nextmmreg-RS_S0+RS_S1,R_SUBFS);
  455. inc(nextmmreg);
  456. end
  457. else
  458. begin
  459. paraloc^.register:=sparesinglereg;
  460. sparesinglereg := NR_NO;
  461. end;
  462. OS_F64:
  463. begin
  464. paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFD);
  465. inc(nextmmreg);
  466. end;
  467. else
  468. internalerror(2012031601);
  469. end;
  470. end
  471. else
  472. begin
  473. { once a floating point parameters has been placed
  474. on the stack we must not pass any more in vfp regs
  475. even if there is a single precision register still
  476. free}
  477. sparesinglereg := NR_NO;
  478. { LOC_REFERENCE always contains everything that's left }
  479. paraloc^.loc:=LOC_REFERENCE;
  480. paraloc^.size:=int_cgsize(paralen);
  481. if (side=callerside) then
  482. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  483. paraloc^.reference.offset:=stack_offset;
  484. inc(stack_offset,align(paralen,4));
  485. paralen:=0;
  486. end;
  487. end;
  488. LOC_REFERENCE:
  489. begin
  490. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  491. begin
  492. paraloc^.size:=OS_ADDR;
  493. assignintreg
  494. end
  495. else
  496. begin
  497. { align stack for eabi }
  498. if (target_info.abi in [abi_eabi,abi_eabihf]) and
  499. firstparaloc and
  500. (paradef.alignment=8) then
  501. stack_offset:=align(stack_offset,8);
  502. paraloc^.size:=paracgsize;
  503. paraloc^.loc:=LOC_REFERENCE;
  504. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  505. paraloc^.reference.offset:=stack_offset;
  506. inc(stack_offset,align(paralen,4));
  507. paralen:=0
  508. end;
  509. end;
  510. else
  511. internalerror(2002071002);
  512. end;
  513. if side=calleeside then
  514. begin
  515. if paraloc^.loc=LOC_REFERENCE then
  516. begin
  517. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  518. { on non-Darwin, the framepointer contains the value
  519. of the stack pointer on entry. On Darwin, the
  520. framepointer points to the previously saved
  521. framepointer (which is followed only by the saved
  522. return address -> framepointer + 4 = stack pointer
  523. on entry }
  524. if not(target_info.system in systems_darwin) then
  525. inc(paraloc^.reference.offset,4)
  526. else
  527. inc(paraloc^.reference.offset,8);
  528. end;
  529. end;
  530. dec(paralen,tcgsize2size[paraloc^.size]);
  531. firstparaloc:=false
  532. end;
  533. end;
  534. curintreg:=nextintreg;
  535. curfloatreg:=nextfloatreg;
  536. curmmreg:=nextmmreg;
  537. cur_stack_offset:=stack_offset;
  538. result:=cur_stack_offset;
  539. end;
  540. function tarmparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  541. var
  542. paraloc : pcgparalocation;
  543. retcgsize : tcgsize;
  544. begin
  545. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  546. exit;
  547. paraloc:=result.add_location;
  548. { Return in FPU register? }
  549. if result.def.typ=floatdef then
  550. begin
  551. if target_info.abi = abi_eabihf then
  552. begin
  553. paraloc^.loc:=LOC_MMREGISTER;
  554. case retcgsize of
  555. OS_64,
  556. OS_F64:
  557. begin
  558. paraloc^.register:=NR_MM_RESULT_REG;
  559. end;
  560. OS_32,
  561. OS_F32:
  562. begin
  563. paraloc^.register:=NR_S0;
  564. end;
  565. else
  566. internalerror(2012032501);
  567. end;
  568. paraloc^.size:=retcgsize;
  569. end
  570. else if (p.proccalloption in [pocall_softfloat]) or
  571. (cs_fp_emulation in current_settings.moduleswitches) or
  572. (current_settings.fputype in [fpu_vfpv2,fpu_vfpv3,fpu_vfpv3_d16,fpu_fpv4_s16]) then
  573. begin
  574. case retcgsize of
  575. OS_64,
  576. OS_F64:
  577. begin
  578. paraloc^.loc:=LOC_REGISTER;
  579. if target_info.endian = endian_big then
  580. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  581. else
  582. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
  583. paraloc^.size:=OS_32;
  584. paraloc:=result.add_location;
  585. paraloc^.loc:=LOC_REGISTER;
  586. if target_info.endian = endian_big then
  587. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  588. else
  589. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
  590. paraloc^.size:=OS_32;
  591. end;
  592. OS_32,
  593. OS_F32:
  594. begin
  595. paraloc^.loc:=LOC_REGISTER;
  596. paraloc^.register:=NR_FUNCTION_RETURN_REG;
  597. paraloc^.size:=OS_32;
  598. end;
  599. else
  600. internalerror(2005082603);
  601. end;
  602. end
  603. else
  604. begin
  605. paraloc^.loc:=LOC_FPUREGISTER;
  606. paraloc^.register:=NR_FPU_RESULT_REG;
  607. paraloc^.size:=retcgsize;
  608. end;
  609. end
  610. { Return in register }
  611. else
  612. begin
  613. if retcgsize in [OS_64,OS_S64] then
  614. begin
  615. paraloc^.loc:=LOC_REGISTER;
  616. if target_info.endian = endian_big then
  617. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  618. else
  619. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
  620. paraloc^.size:=OS_32;
  621. paraloc:=result.add_location;
  622. paraloc^.loc:=LOC_REGISTER;
  623. if target_info.endian = endian_big then
  624. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  625. else
  626. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
  627. paraloc^.size:=OS_32;
  628. end
  629. else
  630. begin
  631. paraloc^.loc:=LOC_REGISTER;
  632. paraloc^.register:=NR_FUNCTION_RETURN_REG;
  633. if (result.intsize<>3) then
  634. paraloc^.size:=retcgsize
  635. else
  636. paraloc^.size:=OS_32;
  637. end;
  638. end;
  639. end;
  640. function tarmparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  641. var
  642. cur_stack_offset: aword;
  643. curintreg, curfloatreg, curmmreg: tsuperregister;
  644. sparesinglereg:tregister;
  645. begin
  646. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
  647. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,false);
  648. create_funcretloc_info(p,side);
  649. end;
  650. function tarmparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  651. var
  652. cur_stack_offset: aword;
  653. curintreg, curfloatreg, curmmreg: tsuperregister;
  654. sparesinglereg:tregister;
  655. begin
  656. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
  657. result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true);
  658. if (p.proccalloption in cstylearrayofconst) then
  659. { just continue loading the parameters in the registers }
  660. result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true)
  661. else
  662. internalerror(200410231);
  663. end;
  664. begin
  665. paramanager:=tarmparamanager.create;
  666. end.