cpupara.pas 14 KB

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