cpupara.pas 36 KB

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