cpupara.pas 31 KB

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