cpupara.pas 20 KB

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