cpupara.pas 20 KB

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