cpupara.pas 20 KB

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