cpupara.pas 19 KB

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