cpupara.pas 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  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 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; 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,
  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_darwin) 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 : {$ifndef VER3_0}tcpuregisterarray{$else}array[0..6] of tsuperregister{$endif} =
  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.getintparaloc(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. (current_settings.fputype in [fpu_vfp_first..fpu_vfp_last]) 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 sym.typ<>fieldvarsym 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. while paralen>0 do
  446. begin
  447. paraloc:=hp.paraloc[side].add_location;
  448. case loc of
  449. LOC_REGISTER:
  450. begin
  451. if paracgsize in [OS_F32,OS_F64,OS_F80] then
  452. case paracgsize of
  453. OS_F32,
  454. OS_F64:
  455. begin
  456. paraloc^.size:=OS_32;
  457. paraloc^.def:=u32inttype;
  458. end;
  459. else
  460. internalerror(2005082901);
  461. end;
  462. { align registers for eabi }
  463. if (target_info.abi in [abi_eabi,abi_eabihf]) and
  464. firstparaloc and
  465. (paradef.alignment=8) then
  466. begin
  467. hp.paraloc[side].Alignment:=8;
  468. if (nextintreg in [RS_R1,RS_R3]) then
  469. inc(nextintreg)
  470. else if nextintreg>RS_R3 then
  471. stack_offset:=align(stack_offset,8);
  472. end;
  473. if nextintreg<=RS_R3 then
  474. begin
  475. paradeftointparaloc(paradef,paracgsize,paraloc^.def,paraloc^.size);
  476. paraloc^.loc:=LOC_REGISTER;
  477. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
  478. inc(nextintreg);
  479. end
  480. else
  481. begin
  482. { LOC_REFERENCE always contains everything that's left as a multiple of 4 bytes}
  483. paraloc^.loc:=LOC_REFERENCE;
  484. paraloc^.def:=get_paraloc_def(paradef,paralen,firstparaloc);
  485. paraloc^.size:=def_cgsize(paraloc^.def);
  486. if (side=callerside) then
  487. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  488. paraloc^.reference.offset:=stack_offset;
  489. inc(stack_offset,align(paralen,4));
  490. paralen:=0;
  491. end;
  492. end;
  493. LOC_FPUREGISTER:
  494. begin
  495. paraloc^.size:=paracgsize;
  496. paraloc^.def:=paradef;
  497. if nextfloatreg<=RS_F3 then
  498. begin
  499. paraloc^.loc:=LOC_FPUREGISTER;
  500. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  501. inc(nextfloatreg);
  502. end
  503. else
  504. begin
  505. paraloc^.loc:=LOC_REFERENCE;
  506. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  507. paraloc^.reference.offset:=stack_offset;
  508. case paraloc^.size of
  509. OS_F32:
  510. inc(stack_offset,4);
  511. OS_F64:
  512. inc(stack_offset,8);
  513. OS_F80:
  514. inc(stack_offset,10);
  515. OS_F128:
  516. inc(stack_offset,16);
  517. else
  518. internalerror(200403201);
  519. end;
  520. end;
  521. end;
  522. LOC_MMREGISTER:
  523. begin
  524. if assigned(hfabasedef) then
  525. begin
  526. paraloc^.def:=hfabasedef;
  527. paraloc^.size:=hfabasesize;
  528. end
  529. else
  530. begin
  531. paraloc^.size:=paracgsize;
  532. paraloc^.def:=paradef;
  533. end;
  534. if (nextmmreg<=RS_D7) or
  535. ((paraloc^.size=OS_F32) and
  536. (sparesinglereg<>NR_NO)) then
  537. begin
  538. paraloc^.loc:=LOC_MMREGISTER;
  539. case paraloc^.size of
  540. OS_F32:
  541. if sparesinglereg = NR_NO then
  542. begin
  543. paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFS);
  544. sparesinglereg:=newreg(R_MMREGISTER,nextmmreg-RS_S0+RS_S1,R_SUBFS);
  545. inc(nextmmreg);
  546. end
  547. else
  548. begin
  549. paraloc^.register:=sparesinglereg;
  550. sparesinglereg := NR_NO;
  551. end;
  552. OS_F64:
  553. begin
  554. paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFD);
  555. inc(nextmmreg);
  556. end;
  557. else
  558. internalerror(2012031601);
  559. end;
  560. end
  561. else
  562. begin
  563. { once a floating point parameters has been placed
  564. on the stack we must not pass any more in vfp regs
  565. even if there is a single precision register still
  566. free}
  567. sparesinglereg := NR_NO;
  568. { LOC_REFERENCE always contains everything that's left }
  569. paraloc^.loc:=LOC_REFERENCE;
  570. paraloc^.size:=int_cgsize(paralen);
  571. if (side=callerside) then
  572. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  573. paraloc^.reference.offset:=stack_offset;
  574. inc(stack_offset,align(paralen,4));
  575. paralen:=0;
  576. end;
  577. end;
  578. LOC_REFERENCE:
  579. begin
  580. paraloc^.size:=paracgsize;
  581. paraloc^.def:=paradef;
  582. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  583. begin
  584. paraloc^.size:=OS_ADDR;
  585. paraloc^.def:=cpointerdef.getreusable_no_free(paradef);
  586. assignintreg
  587. end
  588. else
  589. begin
  590. { align stack for eabi }
  591. if (target_info.abi in [abi_eabi,abi_eabihf]) and
  592. firstparaloc and
  593. (paradef.alignment=8) then
  594. begin
  595. stack_offset:=align(stack_offset,8);
  596. hp.paraloc[side].Alignment:=8;
  597. end;
  598. paraloc^.loc:=LOC_REFERENCE;
  599. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  600. paraloc^.reference.offset:=stack_offset;
  601. inc(stack_offset,align(paralen,4));
  602. paralen:=0
  603. end;
  604. end;
  605. else
  606. internalerror(2002071002);
  607. end;
  608. if side=calleeside then
  609. begin
  610. if paraloc^.loc=LOC_REFERENCE then
  611. begin
  612. paraloc^.reference.index:=current_procinfo.framepointer;
  613. if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
  614. begin
  615. { on non-Darwin, the framepointer contains the value
  616. of the stack pointer on entry. On Darwin, the
  617. framepointer points to the previously saved
  618. framepointer (which is followed only by the saved
  619. return address -> framepointer + 4 = stack pointer
  620. on entry }
  621. if not(target_info.system in systems_darwin) then
  622. inc(paraloc^.reference.offset,4)
  623. else
  624. inc(paraloc^.reference.offset,8);
  625. end;
  626. end;
  627. end;
  628. dec(paralen,tcgsize2size[paraloc^.size]);
  629. firstparaloc:=false
  630. end;
  631. end;
  632. curintreg:=nextintreg;
  633. curfloatreg:=nextfloatreg;
  634. curmmreg:=nextmmreg;
  635. cur_stack_offset:=stack_offset;
  636. result:=cur_stack_offset;
  637. end;
  638. procedure tcpuparamanager.paradeftointparaloc(paradef: tdef; paracgsize: tcgsize; out paralocdef: tdef; out paralocsize: tcgsize);
  639. begin
  640. if not(paracgsize in [OS_32,OS_S32]) or
  641. (paradef.typ in [arraydef,recorddef]) or
  642. is_object(paradef) then
  643. begin
  644. paralocsize:=OS_32;
  645. paralocdef:=u32inttype;
  646. end
  647. else
  648. begin
  649. paralocsize:=paracgsize;
  650. paralocdef:=paradef;
  651. end;
  652. end;
  653. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  654. var
  655. paraloc: pcgparalocation;
  656. retcgsize : tcgsize;
  657. basedef: tdef;
  658. i: longint;
  659. sparesinglereg: tregister;
  660. mmreg : TSuperRegister;
  661. begin
  662. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  663. exit;
  664. paraloc:=result.add_location;
  665. { Return in FPU register? }
  666. basedef:=nil;
  667. sparesinglereg:=NR_NO;
  668. if (result.def.typ=floatdef) or
  669. is_hfa(result.def,basedef) then
  670. begin
  671. if usemmpararegs(p.proccalloption,is_c_variadic(p)) then
  672. begin
  673. if assigned(basedef) then
  674. begin
  675. for i:=2 to result.def.size div basedef.size do
  676. result.add_location;
  677. retcgsize:=def_cgsize(basedef);
  678. end
  679. else
  680. basedef:=result.def;
  681. case retcgsize of
  682. OS_64,
  683. OS_F64:
  684. begin
  685. mmreg:=RS_D0;
  686. end;
  687. OS_32,
  688. OS_F32:
  689. begin
  690. mmreg:=RS_S0;
  691. end;
  692. else
  693. internalerror(2012032501);
  694. end;
  695. repeat
  696. paraloc^.loc:=LOC_MMREGISTER;
  697. { mm registers are strangly ordered in the arm compiler }
  698. case retcgsize of
  699. OS_32,OS_F32:
  700. begin
  701. if sparesinglereg=NR_NO then
  702. begin
  703. paraloc^.register:=newreg(R_MMREGISTER,mmreg,R_SUBFS);
  704. sparesinglereg:=newreg(R_MMREGISTER,mmreg-RS_S0+RS_S1,R_SUBFS);
  705. inc(mmreg);
  706. end
  707. else
  708. begin
  709. paraloc^.register:=sparesinglereg;
  710. sparesinglereg:=NR_NO;
  711. end;
  712. end;
  713. OS_64,OS_F64:
  714. begin
  715. paraloc^.register:=newreg(R_MMREGISTER,mmreg,R_SUBFD);
  716. inc(mmreg);
  717. end;
  718. else
  719. Internalerror(2019081201);
  720. end;
  721. paraloc^.size:=retcgsize;
  722. paraloc^.def:=basedef;
  723. paraloc:=paraloc^.next;
  724. until not assigned(paraloc);
  725. end
  726. else if (p.proccalloption in [pocall_softfloat]) or
  727. (cs_fp_emulation in current_settings.moduleswitches) or
  728. (current_settings.fputype in [fpu_vfp_first..fpu_vfp_last]) then
  729. begin
  730. case retcgsize of
  731. OS_64,
  732. OS_F64:
  733. begin
  734. paraloc^.loc:=LOC_REGISTER;
  735. if target_info.endian = endian_big then
  736. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  737. else
  738. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
  739. paraloc^.size:=OS_32;
  740. paraloc^.def:=u32inttype;
  741. paraloc:=result.add_location;
  742. paraloc^.loc:=LOC_REGISTER;
  743. if target_info.endian = endian_big then
  744. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  745. else
  746. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
  747. paraloc^.size:=OS_32;
  748. paraloc^.def:=u32inttype;
  749. end;
  750. OS_32,
  751. OS_F32:
  752. begin
  753. paraloc^.loc:=LOC_REGISTER;
  754. paraloc^.register:=NR_FUNCTION_RETURN_REG;
  755. paraloc^.size:=OS_32;
  756. paraloc^.def:=u32inttype;
  757. end;
  758. else
  759. internalerror(2005082603);
  760. end;
  761. end
  762. else
  763. begin
  764. paraloc^.loc:=LOC_FPUREGISTER;
  765. paraloc^.register:=NR_FPU_RESULT_REG;
  766. paraloc^.size:=retcgsize;
  767. paraloc^.def:=result.def;
  768. end;
  769. end
  770. { Return in register }
  771. else
  772. begin
  773. if retcgsize in [OS_64,OS_S64] then
  774. begin
  775. paraloc^.loc:=LOC_REGISTER;
  776. if target_info.endian = endian_big then
  777. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  778. else
  779. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
  780. paraloc^.size:=OS_32;
  781. paraloc^.def:=u32inttype;
  782. paraloc:=result.add_location;
  783. paraloc^.loc:=LOC_REGISTER;
  784. if target_info.endian = endian_big then
  785. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  786. else
  787. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
  788. paraloc^.size:=OS_32;
  789. paraloc^.def:=u32inttype;
  790. end
  791. else
  792. begin
  793. paraloc^.loc:=LOC_REGISTER;
  794. paraloc^.register:=NR_FUNCTION_RETURN_REG;
  795. case result.IntSize of
  796. 0:
  797. begin
  798. paraloc^.loc:=LOC_VOID;
  799. paraloc^.register:=NR_NO;
  800. paraloc^.size:=OS_NO;
  801. paraloc^.def:=voidpointertype;
  802. end;
  803. 3:
  804. begin
  805. paraloc^.size:=OS_32;
  806. paraloc^.def:=u32inttype;
  807. end;
  808. else
  809. begin
  810. paradeftointparaloc(result.def,result.size,paraloc^.def,paraloc^.size);
  811. end;
  812. end;
  813. end;
  814. end;
  815. end;
  816. function tcpuparamanager.usemmpararegs(calloption: tproccalloption; variadic: boolean): boolean;
  817. begin
  818. result:=
  819. ((target_info.abi=abi_eabihf) or (calloption=pocall_hardfloat)) and
  820. (not variadic);
  821. end;
  822. function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  823. var
  824. cur_stack_offset: aword;
  825. curintreg, curfloatreg, curmmreg: tsuperregister;
  826. sparesinglereg:tregister;
  827. begin
  828. init_values(p,side,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
  829. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,false);
  830. create_funcretloc_info(p,side);
  831. end;
  832. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;
  833. var
  834. cur_stack_offset: aword;
  835. curintreg, curfloatreg, curmmreg: tsuperregister;
  836. sparesinglereg:tregister;
  837. begin
  838. init_values(p,side,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
  839. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true);
  840. if (p.proccalloption in cstylearrayofconst) then
  841. begin
  842. { just continue loading the parameters in the registers }
  843. if assigned(varargspara) then
  844. begin
  845. if side=callerside then
  846. result:=create_paraloc_info_intern(p,side,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true)
  847. else
  848. internalerror(2019021915);
  849. end;
  850. end
  851. else
  852. internalerror(200410231);
  853. create_funcretloc_info(p,side);
  854. end;
  855. begin
  856. paramanager:=tcpuparamanager.create;
  857. end.