cpupara.pas 17 KB

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