cpupara.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  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. { Generates the argument location information for 680x0.
  18. }
  19. unit cpupara;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. globtype,
  24. cpubase,
  25. aasmdata,
  26. symconst,symtype,symdef,symsym,
  27. parabase,paramgr,cgbase,cgutils;
  28. type
  29. { Returns the location for the nr-st 32 Bit int parameter
  30. if every parameter before is an 32 Bit int parameter as well
  31. and if the calling conventions for the helper routines of the
  32. rtl are used.
  33. }
  34. tm68kparamanager = class(tparamanager)
  35. procedure getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);override;
  36. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  37. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  38. function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
  39. procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);override;
  40. function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
  41. function parseparaloc(p : tparavarsym;const s : string) : boolean;override;
  42. function parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;override;
  43. function get_volatile_registers_int(calloption:tproccalloption):tcpuregisterset;override;
  44. function get_volatile_registers_address(calloption:tproccalloption):tcpuregisterset;override;
  45. private
  46. function parse_loc_string_to_register(var locreg: tregister; const s : string): boolean;
  47. procedure init_values(var curintreg, curfloatreg: tsuperregister; var cur_stack_offset: aword);
  48. function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  49. var curintreg, curfloatreg: tsuperregister; var cur_stack_offset: aword):longint;
  50. end;
  51. implementation
  52. uses
  53. verbose,
  54. globals,
  55. systems,
  56. cpuinfo,
  57. defutil;
  58. function tm68kparamanager.get_volatile_registers_int(calloption:tproccalloption):tcpuregisterset;
  59. begin
  60. { d0 and d1 are considered volatile }
  61. Result:=VOLATILE_INTREGISTERS;
  62. end;
  63. function tm68kparamanager.get_volatile_registers_address(calloption:tproccalloption):tcpuregisterset;
  64. begin
  65. { a0 and a1 are considered volatile }
  66. Result:=VOLATILE_ADDRESSREGISTERS;
  67. end;
  68. procedure tm68kparamanager.getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
  69. var
  70. paraloc : pcgparalocation;
  71. psym: tparavarsym;
  72. pdef: tdef;
  73. begin
  74. if nr<1 then
  75. internalerror(2002070801);
  76. psym:=tparavarsym(pd.paras[nr-1]);
  77. pdef:=psym.vardef;
  78. if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
  79. pdef:=getpointerdef(pdef);
  80. cgpara.reset;
  81. cgpara.size:=def_cgsize(pdef);
  82. cgpara.intsize:=tcgsize2size[cgpara.size];
  83. cgpara.alignment:=std_param_align;
  84. cgpara.def:=pdef;
  85. paraloc:=cgpara.add_location;
  86. with paraloc^ do
  87. begin
  88. { warning : THIS ONLY WORKS WITH INTERNAL ROUTINES,
  89. WHICH MUST ALWAYS PASS 4-BYTE PARAMETERS!!
  90. }
  91. loc:=LOC_REFERENCE;
  92. reference.index:=NR_STACK_POINTER_REG;
  93. reference.offset:=target_info.first_parm_offset+nr*4;
  94. size:=def_cgsize(pdef);
  95. def:=pdef;
  96. end;
  97. end;
  98. function getparaloc(p : tdef) : tcgloc;
  99. begin
  100. result:=LOC_REFERENCE;
  101. (* Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
  102. if push_addr_param for the def is true
  103. case p.typ of
  104. orddef:
  105. result:=LOC_REGISTER;
  106. floatdef:
  107. result:=LOC_FPUREGISTER;
  108. enumdef:
  109. result:=LOC_REGISTER;
  110. pointerdef:
  111. result:=LOC_REGISTER;
  112. formaldef:
  113. result:=LOC_REGISTER;
  114. classrefdef:
  115. result:=LOC_REGISTER;
  116. recorddef:
  117. if (target_info.abi<>abi_powerpc_aix) then
  118. result:=LOC_REFERENCE
  119. else
  120. result:=LOC_REGISTER;
  121. objectdef:
  122. if is_object(p) then
  123. result:=LOC_REFERENCE
  124. else
  125. result:=LOC_REGISTER;
  126. stringdef:
  127. if is_shortstring(p) or is_longstring(p) then
  128. result:=LOC_REFERENCE
  129. else
  130. result:=LOC_REGISTER;
  131. procvardef:
  132. if (po_methodpointer in tprocvardef(p).procoptions) then
  133. result:=LOC_REFERENCE
  134. else
  135. result:=LOC_REGISTER;
  136. filedef:
  137. result:=LOC_REGISTER;
  138. arraydef:
  139. result:=LOC_REFERENCE;
  140. setdef:
  141. if is_smallset(p) then
  142. result:=LOC_REGISTER
  143. else
  144. result:=LOC_REFERENCE;
  145. variantdef:
  146. result:=LOC_REFERENCE;
  147. { avoid problems with errornous definitions }
  148. errordef:
  149. result:=LOC_REGISTER;
  150. else
  151. internalerror(2002071001);
  152. end;
  153. *)
  154. end;
  155. { TODO: copied from ppc cg, needs work}
  156. function tm68kparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  157. begin
  158. result:=false;
  159. { var,out,constref always require address }
  160. if varspez in [vs_var,vs_out,vs_constref] then
  161. begin
  162. result:=true;
  163. exit;
  164. end;
  165. case def.typ of
  166. variantdef,
  167. formaldef :
  168. result:=true;
  169. recorddef:
  170. result:=true;
  171. arraydef:
  172. result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
  173. is_open_array(def) or
  174. is_array_of_const(def) or
  175. is_array_constructor(def);
  176. objectdef :
  177. result:=is_object(def);
  178. setdef :
  179. result:=not is_smallset(def);
  180. stringdef :
  181. result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
  182. procvardef :
  183. result:=po_methodpointer in tprocvardef(def).procoptions;
  184. end;
  185. end;
  186. procedure tm68kparamanager.init_values(var curintreg, curfloatreg: tsuperregister; var cur_stack_offset: aword);
  187. begin
  188. cur_stack_offset:=8;
  189. curintreg:=RS_D0;
  190. curfloatreg:=RS_FP0;
  191. end;
  192. function tm68kparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  193. var
  194. paraloc : pcgparalocation;
  195. retcgsize : tcgsize;
  196. begin
  197. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  198. exit;
  199. { always use the whole 32 bit register when returning values }
  200. if (side=calleeside) and
  201. (result.intsize>0) and
  202. (result.intsize<sizeof(aint)) then
  203. begin
  204. result.def:=sinttype;
  205. result.intsize:=sizeof(aint);
  206. retcgsize:=OS_SINT;
  207. result.size:=retcgsize;
  208. end;
  209. paraloc:=result.add_location;
  210. { Return in FPU register? }
  211. if not (cs_fp_emulation in current_settings.moduleswitches) and
  212. not (current_settings.fputype=fpu_soft) and (result.def.typ=floatdef) then
  213. begin
  214. paraloc^.loc:=LOC_FPUREGISTER;
  215. paraloc^.register:=NR_FPU_RESULT_REG;
  216. paraloc^.size:=retcgsize;
  217. paraloc^.def:=result.def;
  218. end
  219. else
  220. { Return in register }
  221. begin
  222. if retcgsize in [OS_64,OS_S64] then
  223. begin
  224. { low 32bits }
  225. paraloc^.loc:=LOC_REGISTER;
  226. paraloc^.size:=OS_32;
  227. paraloc^.def:=u32inttype;
  228. if side=callerside then
  229. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  230. else
  231. paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
  232. { high 32bits }
  233. paraloc:=result.add_location;
  234. paraloc^.loc:=LOC_REGISTER;
  235. paraloc^.size:=OS_32;
  236. paraloc^.def:=u32inttype;
  237. if side=calleeside then
  238. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  239. else
  240. paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
  241. end
  242. else
  243. begin
  244. paraloc^.loc:=LOC_REGISTER;
  245. paraloc^.size:=retcgsize;
  246. paraloc^.def:=result.def;
  247. if side=callerside then
  248. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
  249. else
  250. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  251. end;
  252. end;
  253. end;
  254. function tm68kparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  255. var
  256. cur_stack_offset: aword;
  257. curintreg, curfloatreg: tsuperregister;
  258. begin
  259. init_values(curintreg,curfloatreg,cur_stack_offset);
  260. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,cur_stack_offset);
  261. create_funcretloc_info(p,side);
  262. end;
  263. function tm68kparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  264. var curintreg, curfloatreg: tsuperregister; var cur_stack_offset: aword):longint;
  265. var
  266. paraloc : pcgparalocation;
  267. hp : tparavarsym;
  268. paracgsize : tcgsize;
  269. paralen : aint;
  270. parasize : longint;
  271. paradef : tdef;
  272. i : longint;
  273. loc : tcgloc;
  274. nextintreg,
  275. nextfloatreg : tsuperregister;
  276. stack_offset : longint;
  277. firstparaloc : boolean;
  278. begin
  279. result:=0;
  280. nextintreg:=curintreg;
  281. nextfloatreg:=curfloatreg;
  282. stack_offset:=cur_stack_offset;
  283. parasize:=0;
  284. for i:=0 to paras.count-1 do
  285. begin
  286. hp:=tparavarsym(paras[i]);
  287. paradef:=hp.vardef;
  288. { syscall for AmigaOS can have already a paraloc set }
  289. if (vo_has_explicit_paraloc in hp.varoptions) then
  290. begin
  291. if not(vo_is_syscall_lib in hp.varoptions) then
  292. internalerror(200506051);
  293. continue;
  294. end;
  295. hp.paraloc[side].reset;
  296. { currently only support C-style array of const }
  297. if (p.proccalloption in cstylearrayofconst) and
  298. is_array_of_const(paradef) then
  299. begin
  300. {$ifdef DEBUG_CHARLIE}
  301. writeln('loc register');
  302. {$endif DEBUG_CHARLIE}
  303. paraloc:=hp.paraloc[side].add_location;
  304. { hack: the paraloc must be valid, but is not actually used }
  305. paraloc^.loc:=LOC_REGISTER;
  306. paraloc^.register:=NR_D0;
  307. paraloc^.size:=OS_ADDR;
  308. paraloc^.def:=voidpointertype;
  309. break;
  310. end;
  311. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  312. begin
  313. {$ifdef DEBUG_CHARLIE}
  314. writeln('loc register');
  315. {$endif DEBUG_CHARLIE}
  316. paradef:=getpointerdef(paradef);
  317. loc:=LOC_REGISTER;
  318. paracgsize := OS_ADDR;
  319. paralen := tcgsize2size[OS_ADDR];
  320. end
  321. else
  322. begin
  323. if not is_special_array(paradef) then
  324. paralen:=paradef.size
  325. else
  326. paralen:=tcgsize2size[def_cgsize(paradef)];
  327. loc:=getparaloc(paradef);
  328. paracgsize:=def_cgsize(paradef);
  329. { for things like formaldef }
  330. if (paracgsize=OS_NO) then
  331. begin
  332. paracgsize:=OS_ADDR;
  333. paralen := tcgsize2size[OS_ADDR];
  334. end;
  335. end;
  336. hp.paraloc[side].alignment:=std_param_align;
  337. hp.paraloc[side].size:=paracgsize;
  338. hp.paraloc[side].intsize:=paralen;
  339. hp.paraloc[side].def:=paradef;
  340. if (paralen = 0) then
  341. if (paradef.typ = recorddef) then
  342. begin
  343. paraloc:=hp.paraloc[side].add_location;
  344. paraloc^.loc := LOC_VOID;
  345. end
  346. else
  347. internalerror(200506052);
  348. firstparaloc:=true;
  349. { can become < 0 for e.g. 3-byte records }
  350. while (paralen > 0) do
  351. begin
  352. paraloc:=hp.paraloc[side].add_location;
  353. (*
  354. by default, the m68k doesn't know any register parameters (FK)
  355. if (loc = LOC_REGISTER) and
  356. (nextintreg <= RS_D2) then
  357. begin
  358. //writeln('loc register');
  359. paraloc^.loc := loc;
  360. { make sure we don't lose whether or not the type is signed }
  361. if (paradef.typ <> orddef) then
  362. paracgsize := int_cgsize(paralen);
  363. if (paracgsize in [OS_NO,OS_64,OS_S64]) then
  364. paraloc^.size := OS_INT
  365. else
  366. paraloc^.size := paracgsize;
  367. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
  368. inc(nextintreg);
  369. dec(paralen,tcgsize2size[paraloc^.size]);
  370. end
  371. else if (loc = LOC_FPUREGISTER) and
  372. (nextfloatreg <= RS_FP2) then
  373. begin
  374. // writeln('loc fpuregister');
  375. paraloc^.loc:=loc;
  376. paraloc^.size := paracgsize;
  377. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  378. inc(nextfloatreg);
  379. dec(paralen,tcgsize2size[paraloc^.size]);
  380. end
  381. else { LOC_REFERENCE }
  382. *)
  383. begin
  384. {$ifdef DEBUG_CHARLIE}
  385. writeln('loc reference');
  386. {$endif DEBUG_CHARLIE}
  387. paraloc^.loc:=LOC_REFERENCE;
  388. paraloc^.def:=get_paraloc_def(paradef,paralen,firstparaloc);
  389. if paradef.typ<>orddef then
  390. paracgsize:=int_cgsize(paralen);
  391. if paracgsize=OS_NO then
  392. paraloc^.size:=OS_INT
  393. else
  394. paraloc^.size:=paracgsize;
  395. if (side = callerside) then
  396. paraloc^.reference.index:=NR_STACK_POINTER_REG
  397. else
  398. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  399. paraloc^.reference.offset:=stack_offset;
  400. inc(stack_offset,align(paralen,4));
  401. paralen := 0;
  402. end;
  403. firstparaloc:=false;
  404. end;
  405. end;
  406. result:=stack_offset;
  407. // writeln('stack offset:',stack_offset);
  408. end;
  409. {
  410. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  411. paracgsize:=OS_ADDR
  412. else
  413. begin
  414. paracgsize:=def_cgsize(paradef);
  415. if paracgsize=OS_NO then
  416. paracgsize:=OS_ADDR;
  417. end;
  418. hp.paraloc[side].size:=paracgsize;
  419. hp.paraloc[side].Alignment:=std_param_align;
  420. paraloc:=hp.paraloc[side].add_location;
  421. paraloc^.size:=paracgsize;
  422. paraloc^.loc:=LOC_REFERENCE;
  423. if side=callerside then
  424. paraloc^.reference.index:=NR_STACK_POINTER_REG
  425. else
  426. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  427. paraloc^.reference.offset:=target_info.first_parm_offset+parasize;
  428. end;
  429. create_funcretloc_info(p,side);
  430. result:=parasize;
  431. end;
  432. }
  433. function tm68kparamanager.parse_loc_string_to_register(var locreg: tregister; const s : string): boolean;
  434. begin
  435. locreg:=std_regnum_search(lowercase(s));
  436. result:=(locreg <> NR_NO) and (locreg <> NR_SP);
  437. end;
  438. function tm68kparamanager.parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;
  439. begin
  440. case target_info.system of
  441. system_m68k_amiga:
  442. result:=parse_loc_string_to_register(p.exp_funcretloc, s);
  443. else
  444. internalerror(2005121801);
  445. end;
  446. end;
  447. function tm68kparamanager.parseparaloc(p : tparavarsym;const s : string) : boolean;
  448. var
  449. paraloc : pcgparalocation;
  450. begin
  451. result:=false;
  452. case target_info.system of
  453. system_m68k_amiga:
  454. begin
  455. p.paraloc[callerside].alignment:=4;
  456. paraloc:=p.paraloc[callerside].add_location;
  457. paraloc^.loc:=LOC_REGISTER;
  458. paraloc^.size:=def_cgsize(p.vardef);
  459. paraloc^.def:=p.vardef;
  460. if not parse_loc_string_to_register(paraloc^.register, s) then
  461. exit;
  462. { copy to callee side }
  463. p.paraloc[calleeside].add_location^:=paraloc^;
  464. end;
  465. else
  466. internalerror(200405092);
  467. end;
  468. result:=true;
  469. end;
  470. procedure tm68kparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);
  471. var
  472. paraloc : pcgparalocation;
  473. begin
  474. paraloc:=parasym.paraloc[callerside].location;
  475. { Never a need for temps when value is pushed (calls inside parameters
  476. will simply allocate even more stack space for their parameters) }
  477. if not(use_fixed_stack) then
  478. can_use_final_stack_loc:=true;
  479. inherited createtempparaloc(list,calloption,parasym,can_use_final_stack_loc,cgpara);
  480. end;
  481. function tm68kparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  482. var
  483. cur_stack_offset: aword;
  484. curintreg, curfloatreg: tsuperregister;
  485. begin
  486. init_values(curintreg,curfloatreg,cur_stack_offset);
  487. result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,cur_stack_offset);
  488. if (p.proccalloption in cstylearrayofconst) then
  489. { just continue loading the parameters in the registers }
  490. result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,cur_stack_offset)
  491. else
  492. internalerror(200410231);
  493. end;
  494. begin
  495. paramanager:=tm68kparamanager.create;
  496. end.