cpupara.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  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. 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;
  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.typ = 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. {
  324. by default, the m68k doesn't know any register parameters (FK)
  325. if (loc = LOC_REGISTER) and
  326. (nextintreg <= RS_D2) then
  327. begin
  328. //writeln('loc register');
  329. paraloc^.loc := loc;
  330. { make sure we don't lose whether or not the type is signed }
  331. if (paradef.typ <> orddef) then
  332. paracgsize := int_cgsize(paralen);
  333. if (paracgsize in [OS_NO,OS_64,OS_S64]) then
  334. paraloc^.size := OS_INT
  335. else
  336. paraloc^.size := paracgsize;
  337. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
  338. inc(nextintreg);
  339. dec(paralen,tcgsize2size[paraloc^.size]);
  340. end
  341. else if (loc = LOC_FPUREGISTER) and
  342. (nextfloatreg <= RS_FP2) then
  343. begin
  344. // writeln('loc fpuregister');
  345. paraloc^.loc:=loc;
  346. paraloc^.size := paracgsize;
  347. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  348. inc(nextfloatreg);
  349. dec(paralen,tcgsize2size[paraloc^.size]);
  350. end
  351. else { LOC_REFERENCE }
  352. }
  353. begin
  354. // writeln('loc reference');
  355. paraloc^.loc:=LOC_REFERENCE;
  356. paraloc^.size:=int_cgsize(paralen);
  357. if (side = callerside) then
  358. paraloc^.reference.index:=NR_STACK_POINTER_REG
  359. else
  360. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  361. paraloc^.reference.offset:=stack_offset;
  362. inc(stack_offset,align(paralen,4));
  363. paralen := 0;
  364. end;
  365. end;
  366. end;
  367. result:=stack_offset;
  368. // writeln('stack offset:',stack_offset);
  369. end;
  370. {
  371. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  372. paracgsize:=OS_ADDR
  373. else
  374. begin
  375. paracgsize:=def_cgsize(paradef);
  376. if paracgsize=OS_NO then
  377. paracgsize:=OS_ADDR;
  378. end;
  379. hp.paraloc[side].size:=paracgsize;
  380. hp.paraloc[side].Alignment:=std_param_align;
  381. paraloc:=hp.paraloc[side].add_location;
  382. paraloc^.size:=paracgsize;
  383. paraloc^.loc:=LOC_REFERENCE;
  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:=target_info.first_parm_offset+parasize;
  389. end;
  390. create_funcretloc_info(p,side);
  391. result:=parasize;
  392. end;
  393. }
  394. function tm68kparamanager.parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;
  395. begin
  396. result:=false;
  397. case target_info.system of
  398. system_m68k_amiga:
  399. begin
  400. if s='D0' then
  401. p.exp_funcretloc:=NR_D0
  402. else if s='D1' then
  403. p.exp_funcretloc:=NR_D1
  404. else if s='D2' then
  405. p.exp_funcretloc:=NR_D2
  406. else if s='D3' then
  407. p.exp_funcretloc:=NR_D3
  408. else if s='D4' then
  409. p.exp_funcretloc:=NR_D4
  410. else if s='D5' then
  411. p.exp_funcretloc:=NR_D5
  412. else if s='D6' then
  413. p.exp_funcretloc:=NR_D6
  414. else if s='D7' then
  415. p.exp_funcretloc:=NR_D7
  416. else if s='A0' then
  417. p.exp_funcretloc:=NR_A0
  418. else if s='A1' then
  419. p.exp_funcretloc:=NR_A1
  420. else if s='A2' then
  421. p.exp_funcretloc:=NR_A2
  422. else if s='A3' then
  423. p.exp_funcretloc:=NR_A3
  424. else if s='A4' then
  425. p.exp_funcretloc:=NR_A4
  426. else if s='A5' then
  427. p.exp_funcretloc:=NR_A5
  428. { 'A6' is problematic, since it's the frame pointer in fpc,
  429. so it should be saved before a call! }
  430. else if s='A6' then
  431. p.exp_funcretloc:=NR_A6
  432. { 'A7' is the stack pointer on 68k, can't be overwritten by API calls }
  433. else
  434. p.exp_funcretloc:=NR_NO;
  435. if p.exp_funcretloc<>NR_NO then result:=true;
  436. end;
  437. else
  438. internalerror(2005121801);
  439. end;
  440. end;
  441. function tm68kparamanager.parseparaloc(p : tparavarsym;const s : string) : boolean;
  442. var
  443. paraloc : pcgparalocation;
  444. begin
  445. result:=false;
  446. case target_info.system of
  447. system_m68k_amiga:
  448. begin
  449. p.paraloc[callerside].alignment:=4;
  450. paraloc:=p.paraloc[callerside].add_location;
  451. paraloc^.loc:=LOC_REGISTER;
  452. paraloc^.size:=def_cgsize(p.vardef);
  453. { pattern is always uppercase'd }
  454. if s='D0' then
  455. paraloc^.register:=NR_D0
  456. else if s='D1' then
  457. paraloc^.register:=NR_D1
  458. else if s='D2' then
  459. paraloc^.register:=NR_D2
  460. else if s='D3' then
  461. paraloc^.register:=NR_D3
  462. else if s='D4' then
  463. paraloc^.register:=NR_D4
  464. else if s='D5' then
  465. paraloc^.register:=NR_D5
  466. else if s='D6' then
  467. paraloc^.register:=NR_D6
  468. else if s='D7' then
  469. paraloc^.register:=NR_D7
  470. else if s='A0' then
  471. paraloc^.register:=NR_A0
  472. else if s='A1' then
  473. paraloc^.register:=NR_A1
  474. else if s='A2' then
  475. paraloc^.register:=NR_A2
  476. else if s='A3' then
  477. paraloc^.register:=NR_A3
  478. else if s='A4' then
  479. paraloc^.register:=NR_A4
  480. else if s='A5' then
  481. paraloc^.register:=NR_A5
  482. { 'A6' is problematic, since it's the frame pointer in fpc,
  483. so it should be saved before a call! }
  484. else if s='A6' then
  485. paraloc^.register:=NR_A6
  486. { 'A7' is the stack pointer on 68k, can't be overwritten by API calls }
  487. else
  488. exit;
  489. { copy to callee side }
  490. p.paraloc[calleeside].add_location^:=paraloc^;
  491. end;
  492. else
  493. internalerror(200405092);
  494. end;
  495. result:=true;
  496. end;
  497. begin
  498. paramanager:=tm68kparamanager.create;
  499. end.