cpupara.pas 35 KB

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