cpupara.pas 29 KB

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