cpupara.pas 28 KB

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