cpupara.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  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;var cgpara:TCGPara);override;
  35. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  36. function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
  37. function get_funcretloc(p : tabstractprocdef; side: tcallercallee; def: tdef): tcgpara;override;
  38. private
  39. procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister);
  40. function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  41. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister; isvariadic: boolean):longint;
  42. procedure create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
  43. end;
  44. implementation
  45. uses
  46. verbose,systems,cutils,
  47. rgobj,
  48. defutil,symsym,symtable;
  49. function tarmparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  50. begin
  51. if (target_info.system<>system_arm_darwin) then
  52. result:=VOLATILE_INTREGISTERS
  53. else
  54. result:=VOLATILE_INTREGISTERS_DARWIN;
  55. end;
  56. function tarmparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  57. begin
  58. result:=VOLATILE_FPUREGISTERS;
  59. end;
  60. function tarmparamanager.get_volatile_registers_mm(calloption: tproccalloption): tcpuregisterset;
  61. begin
  62. result:=VOLATILE_MMREGISTERS;
  63. end;
  64. procedure tarmparamanager.getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);
  65. var
  66. paraloc : pcgparalocation;
  67. begin
  68. if nr<1 then
  69. internalerror(2002070801);
  70. cgpara.reset;
  71. cgpara.size:=OS_ADDR;
  72. cgpara.intsize:=sizeof(pint);
  73. cgpara.alignment:=std_param_align;
  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 [pocall_cdecl,pocall_cppdecl]) 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:=voidpointertype;
  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. end;
  345. end
  346. end;
  347. hp.paraloc[side].size:=paracgsize;
  348. hp.paraloc[side].Alignment:=std_param_align;
  349. hp.paraloc[side].intsize:=paralen;
  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. procedure tarmparamanager.create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
  530. begin
  531. p.funcretloc[side]:=get_funcretloc(p,side,p.returndef);
  532. end;
  533. function tarmparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; def: tdef): tcgpara;
  534. var
  535. paraloc : pcgparalocation;
  536. retcgsize : tcgsize;
  537. begin
  538. if set_common_funcretloc_info(p,def,retcgsize,result) then
  539. exit;
  540. paraloc:=result.add_location;
  541. { Return in FPU register? }
  542. if 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]) 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 [pocall_cdecl,pocall_cppdecl]) 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.