cpupara.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  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. { TODO: 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:=not is_smallset(def);
  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 is passed as var parameter }
  193. if ret_in_param(p.returndef,p.proccalloption) then
  194. begin
  195. p.funcretloc[side].loc:=LOC_REFERENCE;
  196. p.funcretloc[side].size:=retcgsize;
  197. exit;
  198. end;
  199. { Return in FPU register? }
  200. if not(cs_fp_emulation in current_settings.moduleswitches) and (p.returndef.typ=floatdef) then
  201. begin
  202. p.funcretloc[side].loc:=LOC_FPUREGISTER;
  203. p.funcretloc[side].register:=NR_FPU_RESULT_REG;
  204. p.funcretloc[side].size:=retcgsize;
  205. end
  206. else
  207. { Return in register }
  208. begin
  209. if retcgsize in [OS_64,OS_S64] then
  210. begin
  211. { low 32bits }
  212. p.funcretloc[side].loc:=LOC_REGISTER;
  213. p.funcretloc[side].size:=OS_64;
  214. if side=callerside then
  215. p.funcretloc[side].register64.reglo:=NR_FUNCTION_RESULT64_LOW_REG
  216. else
  217. p.funcretloc[side].register64.reglo:=NR_FUNCTION_RETURN64_LOW_REG;
  218. { high 32bits }
  219. if side=calleeside then
  220. p.funcretloc[side].register64.reghi:=NR_FUNCTION_RESULT64_HIGH_REG
  221. else
  222. p.funcretloc[side].register64.reghi:=NR_FUNCTION_RETURN64_HIGH_REG;
  223. end
  224. else
  225. begin
  226. p.funcretloc[side].loc:=LOC_REGISTER;
  227. p.funcretloc[side].size:=retcgsize;
  228. if side=callerside then
  229. p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
  230. else
  231. p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  232. end;
  233. end;
  234. end;
  235. function tm68kparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  236. var
  237. cur_stack_offset: aword;
  238. curintreg, curfloatreg: tsuperregister;
  239. begin
  240. init_values(curintreg,curfloatreg,cur_stack_offset);
  241. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,cur_stack_offset);
  242. create_funcretloc_info(p,side);
  243. end;
  244. function tm68kparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  245. var curintreg, curfloatreg: tsuperregister; var cur_stack_offset: aword):longint;
  246. var
  247. paraloc : pcgparalocation;
  248. hp : tparavarsym;
  249. paracgsize : tcgsize;
  250. paralen : aint;
  251. parasize : longint;
  252. paradef : tdef;
  253. i : longint;
  254. loc : tcgloc;
  255. nextintreg,
  256. nextfloatreg : tsuperregister;
  257. stack_offset : longint;
  258. begin
  259. result:=0;
  260. nextintreg:=curintreg;
  261. nextfloatreg:=curfloatreg;
  262. stack_offset:=cur_stack_offset;
  263. parasize:=0;
  264. for i:=0 to p.paras.count-1 do
  265. begin
  266. hp:=tparavarsym(paras[i]);
  267. paradef:=hp.vardef;
  268. { syscall for AmigaOS can have already a paraloc set }
  269. if (vo_has_explicit_paraloc in hp.varoptions) then
  270. begin
  271. if not(vo_is_syscall_lib in hp.varoptions) then
  272. internalerror(200506051);
  273. continue;
  274. end;
  275. hp.paraloc[side].reset;
  276. { currently only support C-style array of const }
  277. if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
  278. is_array_of_const(paradef) then
  279. begin
  280. {$ifdef DEBUG_CHARLIE}
  281. writeln('loc register');
  282. {$endif DEBUG_CHARLIE}
  283. paraloc:=hp.paraloc[side].add_location;
  284. { hack: the paraloc must be valid, but is not actually used }
  285. paraloc^.loc:=LOC_REGISTER;
  286. paraloc^.register:=NR_D0;
  287. paraloc^.size:=OS_ADDR;
  288. break;
  289. end;
  290. if (hp.varspez in [vs_var,vs_out]) or
  291. push_addr_param(hp.varspez,paradef,p.proccalloption) or
  292. is_open_array(paradef) or
  293. is_array_of_const(paradef) then
  294. begin
  295. {$ifdef DEBUG_CHARLIE}
  296. writeln('loc register');
  297. {$endif DEBUG_CHARLIE}
  298. paradef:=voidpointertype;
  299. loc:=LOC_REGISTER;
  300. paracgsize := OS_ADDR;
  301. paralen := tcgsize2size[OS_ADDR];
  302. end
  303. else
  304. begin
  305. if not is_special_array(paradef) then
  306. paralen:=paradef.size
  307. else
  308. paralen:=tcgsize2size[def_cgsize(paradef)];
  309. loc:=getparaloc(paradef);
  310. paracgsize:=def_cgsize(paradef);
  311. { for things like formaldef }
  312. if (paracgsize=OS_NO) then
  313. begin
  314. paracgsize:=OS_ADDR;
  315. paralen := tcgsize2size[OS_ADDR];
  316. end;
  317. end;
  318. hp.paraloc[side].alignment:=std_param_align;
  319. hp.paraloc[side].size:=paracgsize;
  320. hp.paraloc[side].intsize:=paralen;
  321. if (paralen = 0) then
  322. if (paradef.typ = recorddef) then
  323. begin
  324. paraloc:=hp.paraloc[side].add_location;
  325. paraloc^.loc := LOC_VOID;
  326. end
  327. else
  328. internalerror(200506052);
  329. { can become < 0 for e.g. 3-byte records }
  330. while (paralen > 0) do
  331. begin
  332. paraloc:=hp.paraloc[side].add_location;
  333. {
  334. by default, the m68k doesn't know any register parameters (FK)
  335. if (loc = LOC_REGISTER) and
  336. (nextintreg <= RS_D2) then
  337. begin
  338. //writeln('loc register');
  339. paraloc^.loc := loc;
  340. { make sure we don't lose whether or not the type is signed }
  341. if (paradef.typ <> orddef) then
  342. paracgsize := int_cgsize(paralen);
  343. if (paracgsize in [OS_NO,OS_64,OS_S64]) then
  344. paraloc^.size := OS_INT
  345. else
  346. paraloc^.size := paracgsize;
  347. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
  348. inc(nextintreg);
  349. dec(paralen,tcgsize2size[paraloc^.size]);
  350. end
  351. else if (loc = LOC_FPUREGISTER) and
  352. (nextfloatreg <= RS_FP2) then
  353. begin
  354. // writeln('loc fpuregister');
  355. paraloc^.loc:=loc;
  356. paraloc^.size := paracgsize;
  357. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  358. inc(nextfloatreg);
  359. dec(paralen,tcgsize2size[paraloc^.size]);
  360. end
  361. else { LOC_REFERENCE }
  362. }
  363. begin
  364. {$ifdef DEBUG_CHARLIE}
  365. writeln('loc reference');
  366. {$endif DEBUG_CHARLIE}
  367. paraloc^.loc:=LOC_REFERENCE;
  368. paraloc^.size:=int_cgsize(paralen);
  369. if (side = callerside) then
  370. paraloc^.reference.index:=NR_STACK_POINTER_REG
  371. else
  372. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  373. paraloc^.reference.offset:=stack_offset;
  374. inc(stack_offset,align(paralen,4));
  375. paralen := 0;
  376. end;
  377. end;
  378. end;
  379. result:=stack_offset;
  380. // writeln('stack offset:',stack_offset);
  381. end;
  382. {
  383. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  384. paracgsize:=OS_ADDR
  385. else
  386. begin
  387. paracgsize:=def_cgsize(paradef);
  388. if paracgsize=OS_NO then
  389. paracgsize:=OS_ADDR;
  390. end;
  391. hp.paraloc[side].size:=paracgsize;
  392. hp.paraloc[side].Alignment:=std_param_align;
  393. paraloc:=hp.paraloc[side].add_location;
  394. paraloc^.size:=paracgsize;
  395. paraloc^.loc:=LOC_REFERENCE;
  396. if side=callerside then
  397. paraloc^.reference.index:=NR_STACK_POINTER_REG
  398. else
  399. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  400. paraloc^.reference.offset:=target_info.first_parm_offset+parasize;
  401. end;
  402. create_funcretloc_info(p,side);
  403. result:=parasize;
  404. end;
  405. }
  406. function tm68kparamanager.parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;
  407. begin
  408. result:=false;
  409. case target_info.system of
  410. system_m68k_amiga:
  411. begin
  412. if s='D0' then
  413. p.exp_funcretloc:=NR_D0
  414. else if s='D1' then
  415. p.exp_funcretloc:=NR_D1
  416. else if s='D2' then
  417. p.exp_funcretloc:=NR_D2
  418. else if s='D3' then
  419. p.exp_funcretloc:=NR_D3
  420. else if s='D4' then
  421. p.exp_funcretloc:=NR_D4
  422. else if s='D5' then
  423. p.exp_funcretloc:=NR_D5
  424. else if s='D6' then
  425. p.exp_funcretloc:=NR_D6
  426. else if s='D7' then
  427. p.exp_funcretloc:=NR_D7
  428. else if s='A0' then
  429. p.exp_funcretloc:=NR_A0
  430. else if s='A1' then
  431. p.exp_funcretloc:=NR_A1
  432. else if s='A2' then
  433. p.exp_funcretloc:=NR_A2
  434. else if s='A3' then
  435. p.exp_funcretloc:=NR_A3
  436. else if s='A4' then
  437. p.exp_funcretloc:=NR_A4
  438. else if s='A5' then
  439. p.exp_funcretloc:=NR_A5
  440. { 'A6' is problematic, since it's the frame pointer in fpc,
  441. so it should be saved before a call! }
  442. else if s='A6' then
  443. p.exp_funcretloc:=NR_A6
  444. { 'A7' is the stack pointer on 68k, can't be overwritten by API calls }
  445. else
  446. p.exp_funcretloc:=NR_NO;
  447. if p.exp_funcretloc<>NR_NO then result:=true;
  448. end;
  449. else
  450. internalerror(2005121801);
  451. end;
  452. end;
  453. function tm68kparamanager.parseparaloc(p : tparavarsym;const s : string) : boolean;
  454. var
  455. paraloc : pcgparalocation;
  456. begin
  457. result:=false;
  458. case target_info.system of
  459. system_m68k_amiga:
  460. begin
  461. p.paraloc[callerside].alignment:=4;
  462. paraloc:=p.paraloc[callerside].add_location;
  463. paraloc^.loc:=LOC_REGISTER;
  464. paraloc^.size:=def_cgsize(p.vardef);
  465. { pattern is always uppercase'd }
  466. if s='D0' then
  467. paraloc^.register:=NR_D0
  468. else if s='D1' then
  469. paraloc^.register:=NR_D1
  470. else if s='D2' then
  471. paraloc^.register:=NR_D2
  472. else if s='D3' then
  473. paraloc^.register:=NR_D3
  474. else if s='D4' then
  475. paraloc^.register:=NR_D4
  476. else if s='D5' then
  477. paraloc^.register:=NR_D5
  478. else if s='D6' then
  479. paraloc^.register:=NR_D6
  480. else if s='D7' then
  481. paraloc^.register:=NR_D7
  482. else if s='A0' then
  483. paraloc^.register:=NR_A0
  484. else if s='A1' then
  485. paraloc^.register:=NR_A1
  486. else if s='A2' then
  487. paraloc^.register:=NR_A2
  488. else if s='A3' then
  489. paraloc^.register:=NR_A3
  490. else if s='A4' then
  491. paraloc^.register:=NR_A4
  492. else if s='A5' then
  493. paraloc^.register:=NR_A5
  494. { 'A6' is problematic, since it's the frame pointer in fpc,
  495. so it should be saved before a call! }
  496. else if s='A6' then
  497. paraloc^.register:=NR_A6
  498. { 'A7' is the stack pointer on 68k, can't be overwritten by API calls }
  499. else
  500. exit;
  501. { copy to callee side }
  502. p.paraloc[calleeside].add_location^:=paraloc^;
  503. end;
  504. else
  505. internalerror(200405092);
  506. end;
  507. result:=true;
  508. end;
  509. procedure tm68kparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);
  510. var
  511. paraloc : pcgparalocation;
  512. begin
  513. paraloc:=parasym.paraloc[callerside].location;
  514. { No need for temps when value is pushed }
  515. if not(use_fixed_stack) and
  516. assigned(paraloc) and
  517. (paraloc^.loc=LOC_REFERENCE) and
  518. (paraloc^.reference.index=NR_STACK_POINTER_REG) then
  519. duplicateparaloc(list,calloption,parasym,cgpara)
  520. else
  521. inherited createtempparaloc(list,calloption,parasym,cgpara);
  522. end;
  523. begin
  524. paramanager:=tm68kparamanager.create;
  525. end.