cpupara.pas 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  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. if handle_common_ret_in_param(def,pd,result) then
  187. exit;
  188. case def.typ of
  189. recorddef:
  190. begin
  191. result:=def.size>4;
  192. if not result and
  193. (target_info.abi in [abi_default,abi_armeb]) then
  194. begin
  195. { in case of the old ARM abi (APCS), a struct is returned in
  196. a register only if it is simple. And what is a (non-)simple
  197. struct:
  198. "A non-simple type is any non-floating-point type of size
  199. greater than one word (including structures containing only
  200. floating-point fields), and certain single-word structured
  201. types."
  202. (-- ARM APCS documentation)
  203. So only floating point types or more than one word ->
  204. definitely non-simple (more than one word is already
  205. checked above). This includes unions/variant records with
  206. overlaid floating point and integer fields.
  207. Smaller than one word struct types are simple if they are
  208. "integer-like", and:
  209. "A structure is termed integer-like if its size is less than
  210. or equal to one word, and the offset of each of its
  211. addressable subfields is zero."
  212. (-- ARM APCS documentation)
  213. An "addressable subfield" is a field of which you can take
  214. the address, which in practive means any non-bitfield.
  215. In Pascal, there is no way to express the difference that
  216. you can have in C between "char" and "int :8". In this
  217. context, we use the fake distinction that a type defined
  218. inside the record itself (such as "a: 0..255;") indicates
  219. a bitpacked field while a field using a different type
  220. (such as "a: byte;") is not.
  221. }
  222. for i:=0 to trecorddef(def).symtable.SymList.count-1 do
  223. begin
  224. sym:=tsym(trecorddef(def).symtable.SymList[i]);
  225. if sym.typ<>fieldvarsym then
  226. continue;
  227. { bitfield -> ignore }
  228. if (trecordsymtable(trecorddef(def).symtable).usefieldalignment=bit_alignment) and
  229. (tfieldvarsym(sym).vardef.typ in [orddef,enumdef]) and
  230. (tfieldvarsym(sym).vardef.owner.defowner=def) then
  231. continue;
  232. { all other fields must be at offset zero }
  233. if tfieldvarsym(sym).fieldoffset<>0 then
  234. begin
  235. result:=true;
  236. exit;
  237. end;
  238. { floating point field -> also by reference }
  239. if tfieldvarsym(sym).vardef.typ=floatdef then
  240. begin
  241. result:=true;
  242. exit;
  243. end;
  244. end;
  245. end;
  246. end;
  247. procvardef:
  248. if not tprocvardef(def).is_addressonly then
  249. result:=true
  250. else
  251. result:=false
  252. else
  253. result:=inherited ret_in_param(def,pd);
  254. end;
  255. end;
  256. procedure tarmparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister);
  257. begin
  258. curintreg:=RS_R0;
  259. curfloatreg:=RS_F0;
  260. curmmreg:=RS_D0;
  261. cur_stack_offset:=0;
  262. sparesinglereg := NR_NO;
  263. end;
  264. function tarmparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  265. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister; isvariadic: boolean):longint;
  266. var
  267. nextintreg,nextfloatreg,nextmmreg : tsuperregister;
  268. paradef : tdef;
  269. paraloc : pcgparalocation;
  270. stack_offset : aword;
  271. hp : tparavarsym;
  272. loc : tcgloc;
  273. paracgsize : tcgsize;
  274. paralen : longint;
  275. i : integer;
  276. firstparaloc: boolean;
  277. procedure assignintreg;
  278. begin
  279. { In case of po_delphi_nested_cc, the parent frame pointer
  280. is always passed on the stack. }
  281. if (nextintreg<=RS_R3) and
  282. (not(vo_is_parentfp in hp.varoptions) or
  283. not(po_delphi_nested_cc in p.procoptions)) then
  284. begin
  285. paraloc^.loc:=LOC_REGISTER;
  286. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
  287. inc(nextintreg);
  288. end
  289. else
  290. begin
  291. paraloc^.loc:=LOC_REFERENCE;
  292. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  293. paraloc^.reference.offset:=stack_offset;
  294. inc(stack_offset,4);
  295. end;
  296. end;
  297. begin
  298. result:=0;
  299. nextintreg:=curintreg;
  300. nextfloatreg:=curfloatreg;
  301. nextmmreg:=curmmreg;
  302. stack_offset:=cur_stack_offset;
  303. for i:=0 to paras.count-1 do
  304. begin
  305. hp:=tparavarsym(paras[i]);
  306. paradef:=hp.vardef;
  307. hp.paraloc[side].reset;
  308. { currently only support C-style array of const,
  309. there should be no location assigned to the vararg array itself }
  310. if (p.proccalloption in cstylearrayofconst) and
  311. is_array_of_const(paradef) then
  312. begin
  313. paraloc:=hp.paraloc[side].add_location;
  314. { hack: the paraloc must be valid, but is not actually used }
  315. paraloc^.loc:=LOC_REGISTER;
  316. paraloc^.register:=NR_R0;
  317. paraloc^.size:=OS_ADDR;
  318. break;
  319. end;
  320. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  321. begin
  322. paradef:=getpointerdef(paradef);
  323. loc:=LOC_REGISTER;
  324. paracgsize := OS_ADDR;
  325. paralen := tcgsize2size[OS_ADDR];
  326. end
  327. else
  328. begin
  329. if not is_special_array(paradef) then
  330. paralen := paradef.size
  331. else
  332. paralen := tcgsize2size[def_cgsize(paradef)];
  333. loc := getparaloc(p.proccalloption,paradef,isvariadic);
  334. if (paradef.typ in [objectdef,arraydef,recorddef]) and
  335. not is_special_array(paradef) and
  336. (hp.varspez in [vs_value,vs_const]) then
  337. paracgsize := int_cgsize(paralen)
  338. else
  339. begin
  340. paracgsize:=def_cgsize(paradef);
  341. { for things like formaldef }
  342. if (paracgsize=OS_NO) then
  343. begin
  344. paracgsize:=OS_ADDR;
  345. paralen:=tcgsize2size[OS_ADDR];
  346. paradef:=voidpointertype;
  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. hp.paraloc[side].def:=paradef;
  354. firstparaloc:=true;
  355. {$ifdef EXTDEBUG}
  356. if paralen=0 then
  357. internalerror(200410311);
  358. {$endif EXTDEBUG}
  359. while paralen>0 do
  360. begin
  361. paraloc:=hp.paraloc[side].add_location;
  362. if (loc=LOC_REGISTER) and (paracgsize in [OS_F32,OS_F64,OS_F80]) then
  363. case paracgsize of
  364. OS_F32:
  365. paraloc^.size:=OS_32;
  366. OS_F64:
  367. paraloc^.size:=OS_32;
  368. else
  369. internalerror(2005082901);
  370. end
  371. else if (paracgsize in [OS_NO,OS_64,OS_S64]) then
  372. paraloc^.size := OS_32
  373. else
  374. paraloc^.size:=paracgsize;
  375. case loc of
  376. LOC_REGISTER:
  377. begin
  378. { align registers for eabi }
  379. if (target_info.abi in [abi_eabi,abi_eabihf]) and
  380. firstparaloc and
  381. (paradef.alignment=8) then
  382. begin
  383. if (nextintreg in [RS_R1,RS_R3]) then
  384. inc(nextintreg)
  385. else if nextintreg>RS_R3 then
  386. stack_offset:=align(stack_offset,8);
  387. end;
  388. { this is not abi compliant
  389. why? (FK) }
  390. if nextintreg<=RS_R3 then
  391. begin
  392. paraloc^.loc:=LOC_REGISTER;
  393. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
  394. inc(nextintreg);
  395. end
  396. else
  397. begin
  398. { LOC_REFERENCE always contains everything that's left }
  399. paraloc^.loc:=LOC_REFERENCE;
  400. paraloc^.size:=int_cgsize(paralen);
  401. if (side=callerside) then
  402. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  403. paraloc^.reference.offset:=stack_offset;
  404. inc(stack_offset,align(paralen,4));
  405. paralen:=0;
  406. end;
  407. end;
  408. LOC_FPUREGISTER:
  409. begin
  410. if nextfloatreg<=RS_F3 then
  411. begin
  412. paraloc^.loc:=LOC_FPUREGISTER;
  413. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  414. inc(nextfloatreg);
  415. end
  416. else
  417. begin
  418. paraloc^.loc:=LOC_REFERENCE;
  419. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  420. paraloc^.reference.offset:=stack_offset;
  421. case paraloc^.size of
  422. OS_F32:
  423. inc(stack_offset,4);
  424. OS_F64:
  425. inc(stack_offset,8);
  426. OS_F80:
  427. inc(stack_offset,10);
  428. OS_F128:
  429. inc(stack_offset,16);
  430. else
  431. internalerror(200403201);
  432. end;
  433. end;
  434. end;
  435. LOC_MMREGISTER:
  436. begin
  437. if (nextmmreg<=RS_D7) or
  438. ((paraloc^.size = OS_F32) and
  439. (sparesinglereg<>NR_NO)) then
  440. begin
  441. paraloc^.loc:=LOC_MMREGISTER;
  442. case paraloc^.size of
  443. OS_F32:
  444. if sparesinglereg = NR_NO then
  445. begin
  446. paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFS);
  447. sparesinglereg:=newreg(R_MMREGISTER,nextmmreg-RS_S0+RS_S1,R_SUBFS);
  448. inc(nextmmreg);
  449. end
  450. else
  451. begin
  452. paraloc^.register:=sparesinglereg;
  453. sparesinglereg := NR_NO;
  454. end;
  455. OS_F64:
  456. begin
  457. paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFD);
  458. inc(nextmmreg);
  459. end;
  460. else
  461. internalerror(2012031601);
  462. end;
  463. end
  464. else
  465. begin
  466. { once a floating point parameters has been placed
  467. on the stack we must not pass any more in vfp regs
  468. even if there is a single precision register still
  469. free}
  470. sparesinglereg := NR_NO;
  471. { LOC_REFERENCE always contains everything that's left }
  472. paraloc^.loc:=LOC_REFERENCE;
  473. paraloc^.size:=int_cgsize(paralen);
  474. if (side=callerside) then
  475. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  476. paraloc^.reference.offset:=stack_offset;
  477. inc(stack_offset,align(paralen,4));
  478. paralen:=0;
  479. end;
  480. end;
  481. LOC_REFERENCE:
  482. begin
  483. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  484. begin
  485. paraloc^.size:=OS_ADDR;
  486. assignintreg
  487. end
  488. else
  489. begin
  490. { align stack for eabi }
  491. if (target_info.abi in [abi_eabi,abi_eabihf]) and
  492. firstparaloc and
  493. (paradef.alignment=8) then
  494. stack_offset:=align(stack_offset,8);
  495. paraloc^.size:=paracgsize;
  496. paraloc^.loc:=LOC_REFERENCE;
  497. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  498. paraloc^.reference.offset:=stack_offset;
  499. inc(stack_offset,align(paralen,4));
  500. paralen:=0
  501. end;
  502. end;
  503. else
  504. internalerror(2002071002);
  505. end;
  506. if side=calleeside then
  507. begin
  508. if paraloc^.loc=LOC_REFERENCE then
  509. begin
  510. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  511. { on non-Darwin, the framepointer contains the value
  512. of the stack pointer on entry. On Darwin, the
  513. framepointer points to the previously saved
  514. framepointer (which is followed only by the saved
  515. return address -> framepointer + 4 = stack pointer
  516. on entry }
  517. if not(target_info.system in systems_darwin) then
  518. inc(paraloc^.reference.offset,4)
  519. else
  520. inc(paraloc^.reference.offset,8);
  521. end;
  522. end;
  523. dec(paralen,tcgsize2size[paraloc^.size]);
  524. firstparaloc:=false
  525. end;
  526. end;
  527. curintreg:=nextintreg;
  528. curfloatreg:=nextfloatreg;
  529. curmmreg:=nextmmreg;
  530. cur_stack_offset:=stack_offset;
  531. result:=cur_stack_offset;
  532. end;
  533. function tarmparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  534. var
  535. paraloc : pcgparalocation;
  536. retcgsize : tcgsize;
  537. begin
  538. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  539. exit;
  540. paraloc:=result.add_location;
  541. { Return in FPU register? }
  542. if result.def.typ=floatdef then
  543. begin
  544. if target_info.abi = abi_eabihf then
  545. begin
  546. paraloc^.loc:=LOC_MMREGISTER;
  547. case retcgsize of
  548. OS_64,
  549. OS_F64:
  550. begin
  551. paraloc^.register:=NR_MM_RESULT_REG;
  552. end;
  553. OS_32,
  554. OS_F32:
  555. begin
  556. paraloc^.register:=NR_S0;
  557. end;
  558. else
  559. internalerror(2012032501);
  560. end;
  561. paraloc^.size:=retcgsize;
  562. end
  563. else if (p.proccalloption in [pocall_softfloat]) or
  564. (cs_fp_emulation in current_settings.moduleswitches) or
  565. (current_settings.fputype in [fpu_vfpv2,fpu_vfpv3,fpu_vfpv3_d16,fpu_fpv4_s16]) then
  566. begin
  567. case retcgsize of
  568. OS_64,
  569. OS_F64:
  570. begin
  571. paraloc^.loc:=LOC_REGISTER;
  572. if target_info.endian = endian_big then
  573. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  574. else
  575. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
  576. paraloc^.size:=OS_32;
  577. paraloc:=result.add_location;
  578. paraloc^.loc:=LOC_REGISTER;
  579. if target_info.endian = endian_big then
  580. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  581. else
  582. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
  583. paraloc^.size:=OS_32;
  584. end;
  585. OS_32,
  586. OS_F32:
  587. begin
  588. paraloc^.loc:=LOC_REGISTER;
  589. paraloc^.register:=NR_FUNCTION_RETURN_REG;
  590. paraloc^.size:=OS_32;
  591. end;
  592. else
  593. internalerror(2005082603);
  594. end;
  595. end
  596. else
  597. begin
  598. paraloc^.loc:=LOC_FPUREGISTER;
  599. paraloc^.register:=NR_FPU_RESULT_REG;
  600. paraloc^.size:=retcgsize;
  601. end;
  602. end
  603. { Return in register }
  604. else
  605. begin
  606. if retcgsize in [OS_64,OS_S64] then
  607. begin
  608. paraloc^.loc:=LOC_REGISTER;
  609. if target_info.endian = endian_big then
  610. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  611. else
  612. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
  613. paraloc^.size:=OS_32;
  614. paraloc:=result.add_location;
  615. paraloc^.loc:=LOC_REGISTER;
  616. if target_info.endian = endian_big then
  617. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  618. else
  619. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
  620. paraloc^.size:=OS_32;
  621. end
  622. else
  623. begin
  624. paraloc^.loc:=LOC_REGISTER;
  625. paraloc^.register:=NR_FUNCTION_RETURN_REG;
  626. if (result.intsize<>3) then
  627. paraloc^.size:=retcgsize
  628. else
  629. paraloc^.size:=OS_32;
  630. end;
  631. end;
  632. end;
  633. function tarmparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  634. var
  635. cur_stack_offset: aword;
  636. curintreg, curfloatreg, curmmreg: tsuperregister;
  637. sparesinglereg:tregister;
  638. begin
  639. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
  640. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,false);
  641. create_funcretloc_info(p,side);
  642. end;
  643. function tarmparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  644. var
  645. cur_stack_offset: aword;
  646. curintreg, curfloatreg, curmmreg: tsuperregister;
  647. sparesinglereg:tregister;
  648. begin
  649. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
  650. result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true);
  651. if (p.proccalloption in cstylearrayofconst) then
  652. { just continue loading the parameters in the registers }
  653. result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true)
  654. else
  655. internalerror(200410231);
  656. end;
  657. begin
  658. paramanager:=tarmparamanager.create;
  659. end.