cpupara.pas 21 KB

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