cpupara.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  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; def : tdef; 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; def : tdef; var cgpara : tcgpara);
  65. var
  66. paraloc : pcgparalocation;
  67. begin
  68. if nr<1 then
  69. internalerror(2002070801);
  70. cgpara.reset;
  71. cgpara.size:=def_cgsize(def);
  72. cgpara.intsize:=tcgsize2size[cgpara.size];
  73. cgpara.alignment:=std_param_align;
  74. cgpara.def:=def;
  75. paraloc:=cgpara.add_location;
  76. with paraloc^ do
  77. begin
  78. size:=OS_INT;
  79. { the four first parameters are passed into registers }
  80. if nr<=4 then
  81. begin
  82. loc:=LOC_REGISTER;
  83. register:=newreg(R_INTREGISTER,RS_R0+nr-1,R_SUBWHOLE);
  84. end
  85. else
  86. begin
  87. { the other parameters are passed on the stack }
  88. loc:=LOC_REFERENCE;
  89. reference.index:=NR_STACK_POINTER_REG;
  90. reference.offset:=(nr-5)*4;
  91. end;
  92. end;
  93. end;
  94. function getparaloc(calloption : tproccalloption; p : tdef; isvariadic: boolean) : tcgloc;
  95. begin
  96. { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
  97. if push_addr_param for the def is true
  98. }
  99. case p.typ of
  100. orddef:
  101. getparaloc:=LOC_REGISTER;
  102. floatdef:
  103. if (target_info.abi = abi_eabihf) and
  104. (not isvariadic) then
  105. getparaloc:=LOC_MMREGISTER
  106. else if (calloption in [pocall_cdecl,pocall_cppdecl,pocall_softfloat]) or
  107. (cs_fp_emulation in current_settings.moduleswitches) or
  108. (current_settings.fputype in [fpu_vfpv2,fpu_vfpv3,fpu_vfpv3_d16]) then
  109. { the ARM eabi also allows passing VFP values via VFP registers,
  110. but Mac OS X doesn't seem to do that and linux only does it if
  111. built with the "-mfloat-abi=hard" option }
  112. getparaloc:=LOC_REGISTER
  113. else
  114. getparaloc:=LOC_FPUREGISTER;
  115. enumdef:
  116. getparaloc:=LOC_REGISTER;
  117. pointerdef:
  118. getparaloc:=LOC_REGISTER;
  119. formaldef:
  120. getparaloc:=LOC_REGISTER;
  121. classrefdef:
  122. getparaloc:=LOC_REGISTER;
  123. recorddef:
  124. getparaloc:=LOC_REGISTER;
  125. objectdef:
  126. getparaloc:=LOC_REGISTER;
  127. stringdef:
  128. if is_shortstring(p) or is_longstring(p) then
  129. getparaloc:=LOC_REFERENCE
  130. else
  131. getparaloc:=LOC_REGISTER;
  132. procvardef:
  133. getparaloc:=LOC_REGISTER;
  134. filedef:
  135. getparaloc:=LOC_REGISTER;
  136. arraydef:
  137. getparaloc:=LOC_REFERENCE;
  138. setdef:
  139. if is_smallset(p) then
  140. getparaloc:=LOC_REGISTER
  141. else
  142. getparaloc:=LOC_REFERENCE;
  143. variantdef:
  144. getparaloc:=LOC_REGISTER;
  145. { avoid problems with errornous definitions }
  146. errordef:
  147. getparaloc:=LOC_REGISTER;
  148. else
  149. internalerror(2002071001);
  150. end;
  151. end;
  152. function tarmparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  153. begin
  154. result:=false;
  155. if varspez in [vs_var,vs_out,vs_constref] then
  156. begin
  157. result:=true;
  158. exit;
  159. end;
  160. case def.typ of
  161. objectdef:
  162. result:=is_object(def) and ((varspez=vs_const) or (def.size=0));
  163. recorddef:
  164. { note: should this ever be changed, make sure that const records
  165. are always passed by reference for calloption=pocall_mwpascal }
  166. result:=(varspez=vs_const) or (def.size=0);
  167. variantdef,
  168. formaldef:
  169. result:=true;
  170. arraydef:
  171. result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
  172. is_open_array(def) or
  173. is_array_of_const(def) or
  174. is_array_constructor(def);
  175. setdef :
  176. result:=not is_smallset(def);
  177. stringdef :
  178. result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
  179. end;
  180. end;
  181. function tarmparamanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean;
  182. var
  183. i: longint;
  184. sym: tsym;
  185. fpufield: boolean;
  186. begin
  187. case def.typ of
  188. recorddef:
  189. begin
  190. result:=def.size>4;
  191. if not result and
  192. (target_info.abi in [abi_default,abi_armeb]) then
  193. begin
  194. { in case of the old ARM abi (APCS), a struct is returned in
  195. a register only if it is simple. And what is a (non-)simple
  196. struct:
  197. "A non-simple type is any non-floating-point type of size
  198. greater than one word (including structures containing only
  199. floating-point fields), and certain single-word structured
  200. types."
  201. (-- ARM APCS documentation)
  202. So only floating point types or more than one word ->
  203. definitely non-simple (more than one word is already
  204. checked above). This includes unions/variant records with
  205. overlaid floating point and integer fields.
  206. Smaller than one word struct types are simple if they are
  207. "integer-like", and:
  208. "A structure is termed integer-like if its size is less than
  209. or equal to one word, and the offset of each of its
  210. addressable subfields is zero."
  211. (-- ARM APCS documentation)
  212. An "addressable subfield" is a field of which you can take
  213. the address, which in practive means any non-bitfield.
  214. In Pascal, there is no way to express the difference that
  215. you can have in C between "char" and "int :8". In this
  216. context, we use the fake distinction that a type defined
  217. inside the record itself (such as "a: 0..255;") indicates
  218. a bitpacked field while a field using a different type
  219. (such as "a: byte;") is not.
  220. }
  221. for i:=0 to trecorddef(def).symtable.SymList.count-1 do
  222. begin
  223. sym:=tsym(trecorddef(def).symtable.SymList[i]);
  224. if sym.typ<>fieldvarsym then
  225. continue;
  226. { bitfield -> ignore }
  227. if (trecordsymtable(trecorddef(def).symtable).usefieldalignment=bit_alignment) and
  228. (tfieldvarsym(sym).vardef.typ in [orddef,enumdef]) and
  229. (tfieldvarsym(sym).vardef.owner.defowner=def) then
  230. continue;
  231. { all other fields must be at offset zero }
  232. if tfieldvarsym(sym).fieldoffset<>0 then
  233. begin
  234. result:=true;
  235. exit;
  236. end;
  237. { floating point field -> also by reference }
  238. if tfieldvarsym(sym).vardef.typ=floatdef then
  239. begin
  240. result:=true;
  241. exit;
  242. end;
  243. end;
  244. end;
  245. end;
  246. procvardef:
  247. if not tprocvardef(def).is_addressonly then
  248. result:=true
  249. else
  250. result:=false
  251. else
  252. result:=inherited ret_in_param(def,calloption);
  253. end;
  254. end;
  255. procedure tarmparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister);
  256. begin
  257. curintreg:=RS_R0;
  258. curfloatreg:=RS_F0;
  259. curmmreg:=RS_D0;
  260. cur_stack_offset:=0;
  261. sparesinglereg := NR_NO;
  262. end;
  263. function tarmparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  264. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister; isvariadic: boolean):longint;
  265. var
  266. nextintreg,nextfloatreg,nextmmreg : tsuperregister;
  267. paradef : tdef;
  268. paraloc : pcgparalocation;
  269. stack_offset : aword;
  270. hp : tparavarsym;
  271. loc : tcgloc;
  272. paracgsize : tcgsize;
  273. paralen : longint;
  274. i : integer;
  275. firstparaloc: boolean;
  276. procedure assignintreg;
  277. begin
  278. { In case of po_delphi_nested_cc, the parent frame pointer
  279. is always passed on the stack. }
  280. if (nextintreg<=RS_R3) and
  281. (not(vo_is_parentfp in hp.varoptions) or
  282. not(po_delphi_nested_cc in p.procoptions)) then
  283. begin
  284. paraloc^.loc:=LOC_REGISTER;
  285. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
  286. inc(nextintreg);
  287. end
  288. else
  289. begin
  290. paraloc^.loc:=LOC_REFERENCE;
  291. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  292. paraloc^.reference.offset:=stack_offset;
  293. inc(stack_offset,4);
  294. end;
  295. end;
  296. begin
  297. result:=0;
  298. nextintreg:=curintreg;
  299. nextfloatreg:=curfloatreg;
  300. nextmmreg:=curmmreg;
  301. stack_offset:=cur_stack_offset;
  302. for i:=0 to paras.count-1 do
  303. begin
  304. hp:=tparavarsym(paras[i]);
  305. paradef:=hp.vardef;
  306. hp.paraloc[side].reset;
  307. { currently only support C-style array of const,
  308. there should be no location assigned to the vararg array itself }
  309. if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
  310. is_array_of_const(paradef) then
  311. begin
  312. paraloc:=hp.paraloc[side].add_location;
  313. { hack: the paraloc must be valid, but is not actually used }
  314. paraloc^.loc:=LOC_REGISTER;
  315. paraloc^.register:=NR_R0;
  316. paraloc^.size:=OS_ADDR;
  317. break;
  318. end;
  319. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  320. begin
  321. paradef:=getpointerdef(paradef);
  322. loc:=LOC_REGISTER;
  323. paracgsize := OS_ADDR;
  324. paralen := tcgsize2size[OS_ADDR];
  325. end
  326. else
  327. begin
  328. if not is_special_array(paradef) then
  329. paralen := paradef.size
  330. else
  331. paralen := tcgsize2size[def_cgsize(paradef)];
  332. loc := getparaloc(p.proccalloption,paradef,isvariadic);
  333. if (paradef.typ in [objectdef,arraydef,recorddef]) and
  334. not is_special_array(paradef) and
  335. (hp.varspez in [vs_value,vs_const]) then
  336. paracgsize := int_cgsize(paralen)
  337. else
  338. begin
  339. paracgsize:=def_cgsize(paradef);
  340. { for things like formaldef }
  341. if (paracgsize=OS_NO) then
  342. begin
  343. paracgsize:=OS_ADDR;
  344. paralen:=tcgsize2size[OS_ADDR];
  345. paradef:=voidpointertype;
  346. end;
  347. end
  348. end;
  349. hp.paraloc[side].size:=paracgsize;
  350. hp.paraloc[side].Alignment:=std_param_align;
  351. hp.paraloc[side].intsize:=paralen;
  352. hp.paraloc[side].def:=paradef;
  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. if set_common_funcretloc_info(p,def,retcgsize,result) then
  542. exit;
  543. paraloc:=result.add_location;
  544. { Return in FPU register? }
  545. if def.typ=floatdef then
  546. begin
  547. if target_info.abi = abi_eabihf then
  548. begin
  549. paraloc^.loc:=LOC_MMREGISTER;
  550. case retcgsize of
  551. OS_64,
  552. OS_F64:
  553. begin
  554. paraloc^.register:=NR_MM_RESULT_REG;
  555. end;
  556. OS_32,
  557. OS_F32:
  558. begin
  559. paraloc^.register:=NR_S0;
  560. end;
  561. else
  562. internalerror(2012032501);
  563. end;
  564. paraloc^.size:=retcgsize;
  565. end
  566. else if (p.proccalloption in [pocall_softfloat]) or
  567. (cs_fp_emulation in current_settings.moduleswitches) or
  568. (current_settings.fputype in [fpu_vfpv2,fpu_vfpv3,fpu_vfpv3_d16]) then
  569. begin
  570. case retcgsize of
  571. OS_64,
  572. OS_F64:
  573. begin
  574. paraloc^.loc:=LOC_REGISTER;
  575. if target_info.endian = endian_big then
  576. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  577. else
  578. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
  579. paraloc^.size:=OS_32;
  580. paraloc:=result.add_location;
  581. paraloc^.loc:=LOC_REGISTER;
  582. if target_info.endian = endian_big then
  583. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  584. else
  585. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
  586. paraloc^.size:=OS_32;
  587. end;
  588. OS_32,
  589. OS_F32:
  590. begin
  591. paraloc^.loc:=LOC_REGISTER;
  592. paraloc^.register:=NR_FUNCTION_RETURN_REG;
  593. paraloc^.size:=OS_32;
  594. end;
  595. else
  596. internalerror(2005082603);
  597. end;
  598. end
  599. else
  600. begin
  601. paraloc^.loc:=LOC_FPUREGISTER;
  602. paraloc^.register:=NR_FPU_RESULT_REG;
  603. paraloc^.size:=retcgsize;
  604. end;
  605. end
  606. { Return in register }
  607. else
  608. begin
  609. if retcgsize in [OS_64,OS_S64] then
  610. begin
  611. paraloc^.loc:=LOC_REGISTER;
  612. if target_info.endian = endian_big then
  613. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  614. else
  615. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
  616. paraloc^.size:=OS_32;
  617. paraloc:=result.add_location;
  618. paraloc^.loc:=LOC_REGISTER;
  619. if target_info.endian = endian_big then
  620. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  621. else
  622. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
  623. paraloc^.size:=OS_32;
  624. end
  625. else
  626. begin
  627. paraloc^.loc:=LOC_REGISTER;
  628. paraloc^.register:=NR_FUNCTION_RETURN_REG;
  629. if (result.intsize<>3) then
  630. paraloc^.size:=retcgsize
  631. else
  632. paraloc^.size:=OS_32;
  633. end;
  634. end;
  635. end;
  636. function tarmparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  637. var
  638. cur_stack_offset: aword;
  639. curintreg, curfloatreg, curmmreg: tsuperregister;
  640. sparesinglereg:tregister;
  641. begin
  642. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
  643. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,false);
  644. create_funcretloc_info(p,side);
  645. end;
  646. function tarmparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  647. var
  648. cur_stack_offset: aword;
  649. curintreg, curfloatreg, curmmreg: tsuperregister;
  650. sparesinglereg:tregister;
  651. begin
  652. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
  653. result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true);
  654. if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) then
  655. { just continue loading the parameters in the registers }
  656. result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true)
  657. else
  658. internalerror(200410231);
  659. end;
  660. begin
  661. paramanager:=tarmparamanager.create;
  662. end.