2
0

cpupara.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. {
  2. Copyright (c) 2002 by Florian Klaempfl
  3. Generates the argument location information for 680x0
  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. unit cpupara;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. cpubase,
  23. aasmdata,
  24. symconst,symtype,symdef,symsym,
  25. parabase,paramgr,cgbase,cgutils;
  26. type
  27. { Returns the location for the nr-st 32 Bit int parameter
  28. if every parameter before is an 32 Bit int parameter as well
  29. and if the calling conventions for the helper routines of the
  30. rtl are used.
  31. }
  32. tcpuparamanager = class(tparamanager)
  33. function ret_in_param(def:tdef;pd:tabstractprocdef):boolean;override;
  34. function param_use_paraloc(const cgpara:tcgpara):boolean;override;
  35. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  36. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  37. function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
  38. procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);override;
  39. function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
  40. function parseparaloc(p : tparavarsym;const s : string) : boolean;override;
  41. function parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;override;
  42. function get_volatile_registers_int(calloption:tproccalloption):tcpuregisterset;override;
  43. function get_volatile_registers_address(calloption:tproccalloption):tcpuregisterset;override;
  44. function get_volatile_registers_fpu(calloption:tproccalloption):tcpuregisterset;override;
  45. private
  46. function parse_loc_string_to_register(var locreg: tregister; const s : string): boolean;
  47. function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  48. var cur_stack_offset: aword):longint;
  49. end;
  50. implementation
  51. uses
  52. verbose,
  53. globals,
  54. systems,
  55. cpuinfo,
  56. defutil;
  57. function tcpuparamanager.get_volatile_registers_int(calloption:tproccalloption):tcpuregisterset;
  58. begin
  59. { d0 and d1 are considered volatile }
  60. Result:=VOLATILE_INTREGISTERS;
  61. end;
  62. function tcpuparamanager.get_volatile_registers_address(calloption:tproccalloption):tcpuregisterset;
  63. begin
  64. { a0 and a1 are considered volatile }
  65. Result:=VOLATILE_ADDRESSREGISTERS;
  66. end;
  67. function tcpuparamanager.get_volatile_registers_fpu(calloption:tproccalloption):tcpuregisterset;
  68. begin
  69. { fp0 and fp1 are considered volatile }
  70. Result:=VOLATILE_FPUREGISTERS;
  71. end;
  72. function tcpuparamanager.param_use_paraloc(const cgpara:tcgpara):boolean;
  73. var
  74. paraloc : pcgparalocation;
  75. begin
  76. if not assigned(cgpara.location) then
  77. internalerror(200410102);
  78. result:=true;
  79. { All locations are LOC_REFERENCE }
  80. paraloc:=cgpara.location;
  81. while assigned(paraloc) do
  82. begin
  83. if (paraloc^.loc<>LOC_REFERENCE) then
  84. begin
  85. result:=false;
  86. exit;
  87. end;
  88. paraloc:=paraloc^.next;
  89. end;
  90. end;
  91. { TODO: copied from ppc cg, needs work}
  92. function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  93. begin
  94. result:=false;
  95. { var,out,constref always require address }
  96. if varspez in [vs_var,vs_out,vs_constref] then
  97. begin
  98. result:=true;
  99. exit;
  100. end;
  101. case def.typ of
  102. variantdef,
  103. formaldef :
  104. result:=true;
  105. recorddef:
  106. result:=false;
  107. arraydef:
  108. result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
  109. is_open_array(def) or
  110. is_array_of_const(def) or
  111. is_array_constructor(def);
  112. objectdef :
  113. result:=is_object(def);
  114. setdef :
  115. result:=not is_smallset(def);
  116. stringdef :
  117. result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
  118. procvardef :
  119. { Handling of methods must match that of records }
  120. result:=false;
  121. end;
  122. end;
  123. function tcpuparamanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;
  124. begin
  125. if handle_common_ret_in_param(def,pd,result) then
  126. exit;
  127. case def.typ of
  128. recorddef:
  129. if def.size in [1,2,4] then
  130. begin
  131. result:=false;
  132. exit;
  133. end;
  134. end;
  135. result:=inherited ret_in_param(def,pd);
  136. end;
  137. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  138. var
  139. paraloc : pcgparalocation;
  140. retcgsize : tcgsize;
  141. begin
  142. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  143. exit;
  144. { always use the whole 32 bit register when returning values }
  145. if (side=calleeside) and
  146. (result.intsize>0) and
  147. (result.intsize<sizeof(aint)) then
  148. begin
  149. result.def:=sinttype;
  150. result.intsize:=sizeof(aint);
  151. retcgsize:=OS_SINT;
  152. result.size:=retcgsize;
  153. end;
  154. paraloc:=result.add_location;
  155. { Return in FPU register? }
  156. if not (cs_fp_emulation in current_settings.moduleswitches) and
  157. not (current_settings.fputype=fpu_soft) and (result.def.typ=floatdef) then
  158. begin
  159. paraloc^.loc:=LOC_FPUREGISTER;
  160. paraloc^.register:=NR_FPU_RESULT_REG;
  161. paraloc^.size:=retcgsize;
  162. paraloc^.def:=result.def;
  163. end
  164. else
  165. { Return in register }
  166. begin
  167. if retcgsize in [OS_64,OS_S64] then
  168. begin
  169. { low 32bits }
  170. paraloc^.loc:=LOC_REGISTER;
  171. paraloc^.size:=OS_32;
  172. paraloc^.def:=u32inttype;
  173. if side=callerside then
  174. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  175. else
  176. paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
  177. { high 32bits }
  178. paraloc:=result.add_location;
  179. paraloc^.loc:=LOC_REGISTER;
  180. paraloc^.size:=OS_32;
  181. paraloc^.def:=u32inttype;
  182. if side=calleeside then
  183. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  184. else
  185. paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
  186. end
  187. else
  188. begin
  189. paraloc^.loc:=LOC_REGISTER;
  190. paraloc^.size:=retcgsize;
  191. paraloc^.def:=result.def;
  192. if side=callerside then
  193. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
  194. else
  195. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  196. end;
  197. end;
  198. end;
  199. function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  200. var
  201. cur_stack_offset: aword;
  202. begin
  203. cur_stack_offset:=0;
  204. result:=create_paraloc_info_intern(p,side,p.paras,cur_stack_offset);
  205. create_funcretloc_info(p,side);
  206. end;
  207. function tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  208. var cur_stack_offset: aword):longint;
  209. var
  210. paraloc : pcgparalocation;
  211. hp : tparavarsym;
  212. paracgsize : tcgsize;
  213. paralen : aint;
  214. paradef : tdef;
  215. i : longint;
  216. firstparaloc : boolean;
  217. begin
  218. result:=0;
  219. for i:=0 to paras.count-1 do
  220. begin
  221. hp:=tparavarsym(paras[i]);
  222. paradef:=hp.vardef;
  223. { syscall for AmigaOS can have already a paraloc set }
  224. if (vo_has_explicit_paraloc in hp.varoptions) then
  225. begin
  226. if not(vo_is_syscall_lib in hp.varoptions) then
  227. internalerror(200506051);
  228. continue;
  229. end;
  230. hp.paraloc[side].reset;
  231. { currently only support C-style array of const }
  232. if (p.proccalloption in cstylearrayofconst) and
  233. is_array_of_const(paradef) then
  234. begin
  235. paraloc:=hp.paraloc[side].add_location;
  236. { hack: the paraloc must be valid, but is not actually used }
  237. paraloc^.loc:=LOC_REGISTER;
  238. paraloc^.register:=NR_D0;
  239. paraloc^.size:=OS_ADDR;
  240. paraloc^.def:=voidpointertype;
  241. break;
  242. end;
  243. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  244. begin
  245. paradef:=cpointerdef.getreusable(paradef);
  246. paracgsize := OS_ADDR;
  247. paralen := tcgsize2size[OS_ADDR];
  248. end
  249. else
  250. begin
  251. if not is_special_array(paradef) then
  252. paralen:=paradef.size
  253. else
  254. paralen:=tcgsize2size[def_cgsize(paradef)];
  255. paracgsize:=def_cgsize(paradef);
  256. { for things like formaldef }
  257. if (paracgsize=OS_NO) and (paradef.typ<>recorddef) then
  258. begin
  259. paracgsize:=OS_ADDR;
  260. paralen := tcgsize2size[OS_ADDR];
  261. end;
  262. end;
  263. hp.paraloc[side].alignment:=std_param_align;
  264. hp.paraloc[side].size:=paracgsize;
  265. hp.paraloc[side].intsize:=paralen;
  266. hp.paraloc[side].def:=paradef;
  267. if (paralen = 0) then
  268. if (paradef.typ = recorddef) then
  269. begin
  270. paraloc:=hp.paraloc[side].add_location;
  271. paraloc^.loc := LOC_VOID;
  272. end
  273. else
  274. internalerror(200506052);
  275. firstparaloc:=true;
  276. { can become < 0 for e.g. 3-byte records }
  277. while (paralen > 0) do
  278. begin
  279. paraloc:=hp.paraloc[side].add_location;
  280. paraloc^.loc:=LOC_REFERENCE;
  281. paraloc^.def:=get_paraloc_def(paradef,paralen,firstparaloc);
  282. if (paradef.typ=floatdef) then
  283. paraloc^.size:=int_float_cgsize(paralen)
  284. else
  285. paraloc^.size:=int_cgsize(paralen);
  286. paraloc^.reference.offset:=cur_stack_offset;
  287. if (side = callerside) then
  288. paraloc^.reference.index:=NR_STACK_POINTER_REG
  289. else
  290. begin
  291. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  292. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  293. { M68K is a big-endian target }
  294. if (paralen<tcgsize2size[OS_INT]) then
  295. inc(paraloc^.reference.offset,4-paralen);
  296. end;
  297. inc(cur_stack_offset,align(paralen,4));
  298. paralen := 0;
  299. firstparaloc:=false;
  300. end;
  301. end;
  302. result:=cur_stack_offset;
  303. end;
  304. function tcpuparamanager.parse_loc_string_to_register(var locreg: tregister; const s : string): boolean;
  305. begin
  306. locreg:=std_regnum_search(lowercase(s));
  307. result:=(locreg <> NR_NO) and (locreg <> NR_SP);
  308. end;
  309. function tcpuparamanager.parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;
  310. begin
  311. case target_info.system of
  312. system_m68k_amiga:
  313. result:=parse_loc_string_to_register(p.exp_funcretloc, s);
  314. else
  315. internalerror(2005121801);
  316. end;
  317. end;
  318. function tcpuparamanager.parseparaloc(p : tparavarsym;const s : string) : boolean;
  319. var
  320. paraloc : pcgparalocation;
  321. begin
  322. result:=false;
  323. case target_info.system of
  324. system_m68k_amiga:
  325. begin
  326. p.paraloc[callerside].alignment:=4;
  327. paraloc:=p.paraloc[callerside].add_location;
  328. paraloc^.loc:=LOC_REGISTER;
  329. paraloc^.size:=def_cgsize(p.vardef);
  330. paraloc^.def:=p.vardef;
  331. if not parse_loc_string_to_register(paraloc^.register, s) then
  332. exit;
  333. { copy to callee side }
  334. p.paraloc[calleeside].add_location^:=paraloc^;
  335. end;
  336. else
  337. internalerror(200405092);
  338. end;
  339. result:=true;
  340. end;
  341. procedure tcpuparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);
  342. begin
  343. { Never a need for temps when value is pushed (calls inside parameters
  344. will simply allocate even more stack space for their parameters) }
  345. if not(use_fixed_stack) then
  346. can_use_final_stack_loc:=true;
  347. inherited createtempparaloc(list,calloption,parasym,can_use_final_stack_loc,cgpara);
  348. end;
  349. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  350. var
  351. cur_stack_offset: aword;
  352. begin
  353. cur_stack_offset:=0;
  354. result:=create_paraloc_info_intern(p,callerside,p.paras,cur_stack_offset);
  355. if (p.proccalloption in cstylearrayofconst) then
  356. { just continue loading the parameters in the registers }
  357. result:=create_paraloc_info_intern(p,callerside,varargspara,cur_stack_offset)
  358. else
  359. internalerror(200410231);
  360. end;
  361. begin
  362. paramanager:=tcpuparamanager.create;
  363. end.