cpupara.pas 28 KB

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