cpupara.pas 31 KB

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