cpupara.pas 31 KB

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