cpupara.pas 32 KB

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