cpupara.pas 15 KB

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