cpupara.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  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.deftype 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.deftype 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).string_typ 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.rettype.def);
  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.rettype.def) then
  185. begin
  186. location_reset(p.funcretloc[side],LOC_VOID,OS_NO);
  187. exit;
  188. end;
  189. { Return in FPU register? }
  190. if p.rettype.def.deftype=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.rettype.def,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.vartype.def;
  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. paraloc:=hp.paraloc[side].add_location;
  277. { hack: the paraloc must be valid, but is not actually used }
  278. paraloc^.loc:=LOC_REGISTER;
  279. paraloc^.register:=NR_D0;
  280. paraloc^.size:=OS_ADDR;
  281. break;
  282. end;
  283. if (hp.varspez in [vs_var,vs_out]) or
  284. push_addr_param(hp.varspez,paradef,p.proccalloption) or
  285. is_open_array(paradef) or
  286. is_array_of_const(paradef) then
  287. begin
  288. paradef:=voidpointertype.def;
  289. loc:=LOC_REGISTER;
  290. paracgsize := OS_ADDR;
  291. paralen := tcgsize2size[OS_ADDR];
  292. end
  293. else
  294. begin
  295. if not is_special_array(paradef) then
  296. paralen:=paradef.size
  297. else
  298. paralen:=tcgsize2size[def_cgsize(paradef)];
  299. loc:=getparaloc(paradef);
  300. paracgsize:=def_cgsize(paradef);
  301. { for things like formaldef }
  302. if (paracgsize=OS_NO) then
  303. begin
  304. paracgsize:=OS_ADDR;
  305. paralen := tcgsize2size[OS_ADDR];
  306. end;
  307. end;
  308. hp.paraloc[side].alignment:=std_param_align;
  309. hp.paraloc[side].size:=paracgsize;
  310. hp.paraloc[side].intsize:=paralen;
  311. if (paralen = 0) then
  312. if (paradef.deftype = recorddef) then
  313. begin
  314. paraloc:=hp.paraloc[side].add_location;
  315. paraloc^.loc := LOC_VOID;
  316. end
  317. else
  318. internalerror(200506052);
  319. { can become < 0 for e.g. 3-byte records }
  320. while (paralen > 0) do
  321. begin
  322. paraloc:=hp.paraloc[side].add_location;
  323. if (loc = LOC_REGISTER) and
  324. (nextintreg <= RS_D7) then
  325. begin
  326. //writeln('loc register');
  327. paraloc^.loc := loc;
  328. { make sure we don't lose whether or not the type is signed }
  329. if (paradef.deftype <> orddef) then
  330. paracgsize := int_cgsize(paralen);
  331. if (paracgsize in [OS_NO,OS_64,OS_S64]) then
  332. paraloc^.size := OS_INT
  333. else
  334. paraloc^.size := paracgsize;
  335. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
  336. inc(nextintreg);
  337. dec(paralen,tcgsize2size[paraloc^.size]);
  338. end
  339. else if (loc = LOC_FPUREGISTER) and
  340. (nextfloatreg <= RS_FP7) then
  341. begin
  342. writeln('loc fpuregister');
  343. paraloc^.loc:=loc;
  344. paraloc^.size := paracgsize;
  345. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  346. inc(nextfloatreg);
  347. dec(paralen,tcgsize2size[paraloc^.size]);
  348. end
  349. else { LOC_REFERENCE }
  350. begin
  351. writeln('loc reference');
  352. paraloc^.loc:=LOC_REFERENCE;
  353. paraloc^.size:=int_cgsize(paralen);
  354. if (side = callerside) then
  355. paraloc^.reference.index:=NR_STACK_POINTER_REG
  356. else
  357. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  358. paraloc^.reference.offset:=stack_offset;
  359. inc(stack_offset,align(paralen,4));
  360. paralen := 0;
  361. end;
  362. end;
  363. end;
  364. result:=stack_offset;
  365. // writeln('stack offset:',stack_offset);
  366. end;
  367. {
  368. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  369. paracgsize:=OS_ADDR
  370. else
  371. begin
  372. paracgsize:=def_cgsize(paradef);
  373. if paracgsize=OS_NO then
  374. paracgsize:=OS_ADDR;
  375. end;
  376. hp.paraloc[side].size:=paracgsize;
  377. hp.paraloc[side].Alignment:=std_param_align;
  378. paraloc:=hp.paraloc[side].add_location;
  379. paraloc^.size:=paracgsize;
  380. paraloc^.loc:=LOC_REFERENCE;
  381. if side=callerside then
  382. paraloc^.reference.index:=NR_STACK_POINTER_REG
  383. else
  384. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  385. paraloc^.reference.offset:=target_info.first_parm_offset+parasize;
  386. end;
  387. create_funcretloc_info(p,side);
  388. result:=parasize;
  389. end;
  390. }
  391. function tm68kparamanager.parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;
  392. begin
  393. result:=false;
  394. case target_info.system of
  395. system_m68k_amiga:
  396. begin
  397. if s='D0' then
  398. p.exp_funcretloc:=NR_D0
  399. else if s='D1' then
  400. p.exp_funcretloc:=NR_D1
  401. else if s='D2' then
  402. p.exp_funcretloc:=NR_D2
  403. else if s='D3' then
  404. p.exp_funcretloc:=NR_D3
  405. else if s='D4' then
  406. p.exp_funcretloc:=NR_D4
  407. else if s='D5' then
  408. p.exp_funcretloc:=NR_D5
  409. else if s='D6' then
  410. p.exp_funcretloc:=NR_D6
  411. else if s='D7' then
  412. p.exp_funcretloc:=NR_D7
  413. else if s='A0' then
  414. p.exp_funcretloc:=NR_A0
  415. else if s='A1' then
  416. p.exp_funcretloc:=NR_A1
  417. else if s='A2' then
  418. p.exp_funcretloc:=NR_A2
  419. else if s='A3' then
  420. p.exp_funcretloc:=NR_A3
  421. else if s='A4' then
  422. p.exp_funcretloc:=NR_A4
  423. else if s='A5' then
  424. p.exp_funcretloc:=NR_A5
  425. { 'A6' is problematic, since it's the frame pointer in fpc,
  426. so it should be saved before a call! }
  427. else if s='A6' then
  428. p.exp_funcretloc:=NR_A6
  429. { 'A7' is the stack pointer on 68k, can't be overwritten by API calls }
  430. else
  431. p.exp_funcretloc:=NR_NO;
  432. if p.exp_funcretloc<>NR_NO then result:=true;
  433. end;
  434. else
  435. internalerror(2005121801);
  436. end;
  437. end;
  438. function tm68kparamanager.parseparaloc(p : tparavarsym;const s : string) : boolean;
  439. var
  440. paraloc : pcgparalocation;
  441. begin
  442. result:=false;
  443. case target_info.system of
  444. system_m68k_amiga:
  445. begin
  446. p.paraloc[callerside].alignment:=4;
  447. paraloc:=p.paraloc[callerside].add_location;
  448. paraloc^.loc:=LOC_REGISTER;
  449. paraloc^.size:=def_cgsize(p.vartype.def);
  450. { pattern is always uppercase'd }
  451. if s='D0' then
  452. paraloc^.register:=NR_D0
  453. else if s='D1' then
  454. paraloc^.register:=NR_D1
  455. else if s='D2' then
  456. paraloc^.register:=NR_D2
  457. else if s='D3' then
  458. paraloc^.register:=NR_D3
  459. else if s='D4' then
  460. paraloc^.register:=NR_D4
  461. else if s='D5' then
  462. paraloc^.register:=NR_D5
  463. else if s='D6' then
  464. paraloc^.register:=NR_D6
  465. else if s='D7' then
  466. paraloc^.register:=NR_D7
  467. else if s='A0' then
  468. paraloc^.register:=NR_A0
  469. else if s='A1' then
  470. paraloc^.register:=NR_A1
  471. else if s='A2' then
  472. paraloc^.register:=NR_A2
  473. else if s='A3' then
  474. paraloc^.register:=NR_A3
  475. else if s='A4' then
  476. paraloc^.register:=NR_A4
  477. else if s='A5' then
  478. paraloc^.register:=NR_A5
  479. { 'A6' is problematic, since it's the frame pointer in fpc,
  480. so it should be saved before a call! }
  481. else if s='A6' then
  482. paraloc^.register:=NR_A6
  483. { 'A7' is the stack pointer on 68k, can't be overwritten by API calls }
  484. else
  485. exit;
  486. { copy to callee side }
  487. p.paraloc[calleeside].add_location^:=paraloc^;
  488. end;
  489. else
  490. internalerror(200405092);
  491. end;
  492. result:=true;
  493. end;
  494. begin
  495. paramanager:=tm68kparamanager.create;
  496. end.