cg68kcal.pas 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. Generate m68k assembler for in call nodes
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cg68kcal;
  19. interface
  20. uses
  21. symtable,tree;
  22. { save the size of pushed parameter }
  23. var
  24. pushedparasize : longint;
  25. procedure secondcallparan(var p : ptree;defcoll : pdefcoll;
  26. push_from_left_to_right : boolean);
  27. procedure secondcalln(var p : ptree);
  28. procedure secondprocinline(var p : ptree);
  29. implementation
  30. uses
  31. cobjects,verbose,globals,systems,
  32. aasm,types,
  33. hcodegen,temp_gen,pass_2,
  34. m68k,cga68k,tgen68k,cg68kld;
  35. {*****************************************************************************
  36. SecondCallParaN
  37. *****************************************************************************}
  38. procedure secondcallparan(var p : ptree;defcoll : pdefcoll;
  39. push_from_left_to_right : boolean);
  40. procedure maybe_push_open_array_high;
  41. var
  42. r : preference;
  43. begin
  44. { open array ? }
  45. { defcoll^.data can be nil for read/write }
  46. if assigned(defcoll^.data) and
  47. is_open_array(defcoll^.data) then
  48. begin
  49. inc(pushedparasize,4);
  50. { push high }
  51. if is_open_array(p^.left^.resulttype) then
  52. begin
  53. new(r);
  54. reset_reference(r^);
  55. r^.base:=highframepointer;
  56. r^.offset:=highoffset+4;
  57. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_SPPUSH)));
  58. end
  59. else
  60. push_int(parraydef(p^.left^.resulttype)^.highrange-parraydef(p^.left^.resulttype)^.lowrange);
  61. end;
  62. end;
  63. var
  64. size : longint;
  65. stackref : treference;
  66. otlabel,hlabel,oflabel : plabel;
  67. { temporary variables: }
  68. reg : tregister;
  69. tempdeftype : tdeftype;
  70. tempreference : treference;
  71. r : preference;
  72. s : topsize;
  73. op : tasmop;
  74. begin
  75. { push from left to right if specified }
  76. if push_from_left_to_right and assigned(p^.right) then
  77. secondcallparan(p^.right,defcoll^.next,push_from_left_to_right);
  78. otlabel:=truelabel;
  79. oflabel:=falselabel;
  80. getlabel(truelabel);
  81. getlabel(falselabel);
  82. secondpass(p^.left);
  83. { in codegen.handleread.. defcoll^.data is set to nil }
  84. if assigned(defcoll^.data) and
  85. (defcoll^.data^.deftype=formaldef) then
  86. begin
  87. { allow @var }
  88. if p^.left^.treetype=addrn then
  89. begin
  90. { allways a register }
  91. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,p^.left^.location.register,R_SPPUSH)));
  92. ungetregister32(p^.left^.location.register);
  93. end
  94. else
  95. begin
  96. if (p^.left^.location.loc<>LOC_REFERENCE) and
  97. (p^.left^.location.loc<>LOC_MEM) then
  98. CGMessage(type_e_mismatch)
  99. else
  100. begin
  101. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  102. del_reference(p^.left^.location.reference);
  103. end;
  104. end;
  105. inc(pushedparasize,4);
  106. end
  107. { handle call by reference parameter }
  108. else if (defcoll^.paratyp=vs_var) then
  109. begin
  110. if (p^.left^.location.loc<>LOC_REFERENCE) then
  111. CGMessage(cg_e_var_must_be_reference);
  112. maybe_push_open_array_high;
  113. inc(pushedparasize,4);
  114. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  115. del_reference(p^.left^.location.reference);
  116. end
  117. else
  118. begin
  119. tempdeftype:=p^.resulttype^.deftype;
  120. if tempdeftype=filedef then
  121. CGMessage(cg_e_file_must_call_by_reference);
  122. if (defcoll^.paratyp=vs_const) and
  123. dont_copy_const_param(p^.resulttype) then
  124. begin
  125. maybe_push_open_array_high;
  126. inc(pushedparasize,4);
  127. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  128. del_reference(p^.left^.location.reference);
  129. end
  130. else
  131. case p^.left^.location.loc of
  132. LOC_REGISTER,
  133. LOC_CREGISTER : begin
  134. { HERE IS A BIG PROBLEM }
  135. { --> We *MUST* know the data size to push }
  136. { for the moment, we can say that the savesize }
  137. { indicates the parameter size to push, but }
  138. { that is CERTAINLY NOT TRUE! }
  139. { CAN WE USE LIKE LOC_MEM OR LOC_REFERENCE?? }
  140. case integer(p^.left^.resulttype^.savesize) of
  141. 1 : Begin
  142. { A byte sized value normally increments }
  143. { the SP by 2, BUT because how memory has }
  144. { been setup OR because of GAS, a byte sized }
  145. { push CRASHES the Amiga, therefore, we do it }
  146. { by hand instead. }
  147. { PUSH A WORD SHIFTED LEFT 8 }
  148. reg := getregister32;
  149. emit_reg_reg(A_MOVE, S_B, p^.left^.location.register, reg);
  150. exprasmlist^.concat(new(pai68k,op_const_reg(A_LSL,S_W,
  151. 8, reg)));
  152. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,
  153. reg,R_SPPUSH)));
  154. { offset will be TWO greater }
  155. inc(pushedparasize,2);
  156. ungetregister32(reg);
  157. ungetregister32(p^.left^.location.register);
  158. end;
  159. 2 :
  160. Begin
  161. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,
  162. p^.left^.location.register,R_SPPUSH)));
  163. inc(pushedparasize,2);
  164. ungetregister32(p^.left^.location.register);
  165. end;
  166. 4 : Begin
  167. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,
  168. p^.left^.location.register,R_SPPUSH)));
  169. inc(pushedparasize,4);
  170. ungetregister32(p^.left^.location.register);
  171. end;
  172. else
  173. Begin
  174. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,
  175. p^.left^.location.register,R_SPPUSH)));
  176. inc(pushedparasize,4);
  177. ungetregister32(p^.left^.location.register);
  178. end;
  179. end; { end case }
  180. end;
  181. LOC_FPU : begin
  182. size:=pfloatdef(p^.left^.resulttype)^.size;
  183. inc(pushedparasize,size);
  184. { how now how long a FPU is !! }
  185. if (size > 0) and (size < 9) then
  186. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUBQ,S_L,size,R_SP)))
  187. else
  188. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUBA,
  189. S_L,size,R_SP)));
  190. new(r);
  191. reset_reference(r^);
  192. r^.base:=R_SP;
  193. s:=getfloatsize(pfloatdef(p^.left^.resulttype)^.typ);
  194. if (cs_fp_emulation in aktmoduleswitches) or (s=S_FS) then
  195. begin
  196. { when in emulation mode... }
  197. { only single supported!!! }
  198. exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,
  199. p^.left^.location.fpureg,r)));
  200. end
  201. else
  202. { convert back from extended to normal type }
  203. exprasmlist^.concat(new(pai68k,op_reg_ref(A_FMOVE,s,
  204. p^.left^.location.fpureg,r)));
  205. end;
  206. LOC_REFERENCE,LOC_MEM :
  207. begin
  208. tempreference:=p^.left^.location.reference;
  209. del_reference(p^.left^.location.reference);
  210. case p^.resulttype^.deftype of
  211. enumdef,
  212. orddef : begin
  213. case p^.resulttype^.size of
  214. 4 : begin
  215. emit_push_mem(tempreference);
  216. inc(pushedparasize,4);
  217. end;
  218. 1 : Begin
  219. { We push a BUT, the SP is incremented by 2 }
  220. { as specified in the Motorola Prog's Ref Manual }
  221. { Therefore offet increments BY 2!!! }
  222. { BUG??? ... }
  223. { SWAP OPERANDS: }
  224. if tempreference.isintvalue then
  225. Begin
  226. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_W,
  227. tempreference.offset shl 8,R_SPPUSH)));
  228. end
  229. else
  230. Begin
  231. { A byte sized value normally increments }
  232. { the SP by 2, BUT because how memory has }
  233. { been setup OR because of GAS, a byte sized }
  234. { push CRASHES the Amiga, therefore, we do it }
  235. { by hand instead. }
  236. { PUSH A WORD SHIFTED LEFT 8 }
  237. reg:=getregister32;
  238. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,
  239. newreference(tempreference),reg)));
  240. exprasmlist^.concat(new(pai68k,op_const_reg(A_LSL,S_W,
  241. 8, reg)));
  242. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,
  243. reg,R_SPPUSH)));
  244. ungetregister32(reg);
  245. { exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,
  246. newreference(tempreference),R_SPPUSH))); }
  247. end;
  248. inc(pushedparasize,2);
  249. end;
  250. 2 : begin
  251. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,
  252. newreference(tempreference),R_SPPUSH)));
  253. inc(pushedparasize,2);
  254. end;
  255. end;
  256. end;
  257. floatdef : begin
  258. case pfloatdef(p^.resulttype)^.typ of
  259. f32bit,
  260. s32real :
  261. begin
  262. emit_push_mem(tempreference);
  263. inc(pushedparasize,4);
  264. end;
  265. s64real:
  266. {s64bit }
  267. begin
  268. inc(tempreference.offset,4);
  269. emit_push_mem(tempreference);
  270. dec(tempreference.offset,4);
  271. emit_push_mem(tempreference);
  272. inc(pushedparasize,8);
  273. end;
  274. {$ifdef use48}
  275. s48real : begin
  276. end;
  277. {$endif}
  278. s80real : begin
  279. CGMessage(cg_f_extended_cg68k_not_supported);
  280. { inc(tempreference.offset,6);
  281. emit_push_mem(tempreference);
  282. dec(tempreference.offset,4);
  283. emit_push_mem(tempreference);
  284. dec(tempreference.offset,2);
  285. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,
  286. newreference(tempreference),R_SPPUSH)));
  287. inc(pushedparasize,extended_size);}
  288. end;
  289. end;
  290. end;
  291. pointerdef,procvardef,
  292. classrefdef: begin
  293. emit_push_mem(tempreference);
  294. inc(pushedparasize,4);
  295. end;
  296. arraydef,recorddef,stringdef,setdef,objectdef :
  297. begin
  298. if ((p^.resulttype^.deftype=setdef) and
  299. (psetdef(p^.resulttype)^.settype=smallset)) then
  300. begin
  301. emit_push_mem(tempreference);
  302. inc(pushedparasize,4);
  303. end
  304. else
  305. begin
  306. size:=p^.resulttype^.size;
  307. { Alignment }
  308. {
  309. if (size>=4) and ((size and 3)<>0) then
  310. inc(size,4-(size and 3))
  311. else if (size>=2) and ((size and 1)<>0) then
  312. inc(size,2-(size and 1))
  313. else
  314. if size=1 then size:=2;
  315. }
  316. { create stack space }
  317. if (size > 0) and (size < 9) then
  318. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUBQ,S_L,size,R_SP)))
  319. else
  320. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUBA,
  321. S_L,size,R_SP)));
  322. inc(pushedparasize,size);
  323. { create stack reference }
  324. stackref.symbol := nil;
  325. clear_reference(stackref);
  326. stackref.base:=R_SP;
  327. { produce copy }
  328. if p^.resulttype^.deftype=stringdef then
  329. begin
  330. copystring(stackref,p^.left^.location.reference,
  331. pstringdef(p^.resulttype)^.len);
  332. end
  333. else
  334. begin
  335. concatcopy(p^.left^.location.reference,
  336. stackref,p^.resulttype^.size,true);
  337. end;
  338. end;
  339. end;
  340. else CGMessage(cg_e_illegal_expression);
  341. end;
  342. end;
  343. LOC_JUMP : begin
  344. getlabel(hlabel);
  345. inc(pushedparasize,2);
  346. emitl(A_LABEL,truelabel);
  347. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_W,1 shl 8,R_SPPUSH)));
  348. emitl(A_JMP,hlabel);
  349. emitl(A_LABEL,falselabel);
  350. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_W,0,R_SPPUSH)));
  351. emitl(A_LABEL,hlabel);
  352. end;
  353. LOC_FLAGS : begin
  354. exprasmlist^.concat(new(pai68k,op_reg(flag_2_set[p^.left^.location.resflags],S_B,
  355. R_D0)));
  356. exprasmlist^.concat(new(pai68k,op_reg(A_NEG, S_B, R_D0)));
  357. exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_W,$ff, R_D0)));
  358. inc(pushedparasize,2);
  359. { ----------------- HACK ----------------------- }
  360. { HERE IS THE BYTE SIZED PUSH HACK ONCE AGAIN }
  361. { SHIFT LEFT THE BYTE TO MAKE IT WORK! }
  362. exprasmlist^.concat(new(pai68k,op_const_reg(A_LSL,S_W,8, R_D0)));
  363. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,R_D0,R_SPPUSH)));
  364. end;
  365. end;
  366. end;
  367. freelabel(truelabel);
  368. freelabel(falselabel);
  369. truelabel:=otlabel;
  370. falselabel:=oflabel;
  371. { push from right to left }
  372. if not push_from_left_to_right and assigned(p^.right) then
  373. secondcallparan(p^.right,defcoll^.next,push_from_left_to_right);
  374. end;
  375. {*****************************************************************************
  376. SecondCallN
  377. *****************************************************************************}
  378. procedure secondcalln(var p : ptree);
  379. var
  380. unusedregisters : tregisterset;
  381. pushed : tpushed;
  382. funcretref : treference;
  383. hregister : tregister;
  384. oldpushedparasize : longint;
  385. { true if a5 must be loaded again after the subroutine }
  386. loada5 : boolean;
  387. { true if a virtual method must be called directly }
  388. no_virtual_call : boolean;
  389. { true if we produce a con- or destrutor in a call }
  390. is_con_or_destructor : boolean;
  391. { true if a constructor is called again }
  392. extended_new : boolean;
  393. { adress returned from an I/O-error }
  394. iolabel : plabel;
  395. { lexlevel count }
  396. i : longint;
  397. { help reference pointer }
  398. r : preference;
  399. pp,params : ptree;
  400. { temp register allocation }
  401. reg: tregister;
  402. { help reference pointer }
  403. ref: preference;
  404. label
  405. dont_call;
  406. begin
  407. extended_new:=false;
  408. iolabel:=nil;
  409. loada5:=true;
  410. no_virtual_call:=false;
  411. unusedregisters:=unused;
  412. if not assigned(p^.procdefinition) then
  413. exit;
  414. { only if no proc var }
  415. if not(assigned(p^.right)) then
  416. is_con_or_destructor:=((p^.procdefinition^.options and poconstructor)<>0)
  417. or ((p^.procdefinition^.options and podestructor)<>0);
  418. { proc variables destroy all registers }
  419. if (p^.right=nil) and
  420. { virtual methods too }
  421. ((p^.procdefinition^.options and povirtualmethod)=0) then
  422. begin
  423. if ((p^.procdefinition^.options and poiocheck)<>0) and
  424. ((aktprocsym^.definition^.options and poiocheck)=0) and
  425. (cs_check_io in aktlocalswitches) then
  426. begin
  427. getlabel(iolabel);
  428. emitl(A_LABEL,iolabel);
  429. end
  430. else iolabel:=nil;
  431. { save all used registers }
  432. pushusedregisters(pushed,p^.procdefinition^.usedregisters);
  433. { give used registers through }
  434. usedinproc:=usedinproc or p^.procdefinition^.usedregisters;
  435. end
  436. else
  437. begin
  438. pushusedregisters(pushed,$ffff);
  439. usedinproc:=$ffff;
  440. { no IO check for methods and procedure variables }
  441. iolabel:=nil;
  442. end;
  443. { generate the code for the parameter and push them }
  444. oldpushedparasize:=pushedparasize;
  445. pushedparasize:=0;
  446. if (p^.resulttype<>pdef(voiddef)) and
  447. ret_in_param(p^.resulttype) then
  448. begin
  449. funcretref.symbol:=nil;
  450. {$ifdef test_dest_loc}
  451. if dest_loc_known and (dest_loc_tree=p) and
  452. (dest_loc.loc in [LOC_REFERENCE,LOC_MEM]) then
  453. begin
  454. funcretref:=dest_loc.reference;
  455. if assigned(dest_loc.reference.symbol) then
  456. funcretref.symbol:=stringdup(dest_loc.reference.symbol^);
  457. in_dest_loc:=true;
  458. end
  459. else
  460. {$endif test_dest_loc}
  461. gettempofsizereference(p^.procdefinition^.retdef^.size,funcretref);
  462. end;
  463. if assigned(p^.left) then
  464. begin
  465. pushedparasize:=0;
  466. { be found elsewhere }
  467. if assigned(p^.right) then
  468. secondcallparan(p^.left,pprocvardef(p^.right^.resulttype)^.para1,
  469. (p^.procdefinition^.options and poleftright)<>0)
  470. else
  471. secondcallparan(p^.left,p^.procdefinition^.para1,
  472. (p^.procdefinition^.options and poleftright)<>0);
  473. end;
  474. params:=p^.left;
  475. p^.left:=nil;
  476. if ret_in_param(p^.resulttype) then
  477. begin
  478. emitpushreferenceaddr(exprasmlist,funcretref);
  479. inc(pushedparasize,4);
  480. end;
  481. { overloaded operator have no symtable }
  482. if (p^.right=nil) then
  483. begin
  484. { push self }
  485. if assigned(p^.symtable) and
  486. (p^.symtable^.symtabletype=withsymtable) then
  487. begin
  488. { dirty trick to avoid the secondcall below }
  489. p^.methodpointer:=genzeronode(callparan);
  490. p^.methodpointer^.location.loc:=LOC_REGISTER;
  491. p^.methodpointer^.location.register:=R_A5;
  492. { change dispose type !! }
  493. p^.disposetyp:=dt_mbleft_and_method;
  494. { make a reference }
  495. new(r);
  496. reset_reference(r^);
  497. r^.offset:=p^.symtable^.datasize;
  498. r^.base:=procinfo.framepointer;
  499. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_A5)));
  500. end;
  501. { push self }
  502. if assigned(p^.symtable) and
  503. ((p^.symtable^.symtabletype=objectsymtable) or
  504. (p^.symtable^.symtabletype=withsymtable)) then
  505. begin
  506. if assigned(p^.methodpointer) then
  507. begin
  508. case p^.methodpointer^.treetype of
  509. typen : begin
  510. { direct call to inherited method }
  511. if (p^.procdefinition^.options and poabstractmethod)<>0 then
  512. begin
  513. CGMessage(cg_e_cant_call_abstract_method);
  514. goto dont_call;
  515. end;
  516. { generate no virtual call }
  517. no_virtual_call:=true;
  518. if (p^.symtableprocentry^.properties and sp_static)<>0 then
  519. begin
  520. { well lets put the VMT address directly into a5 }
  521. { it is kind of dirty but that is the simplest }
  522. { way to accept virtual static functions (PM) }
  523. loada5:=true;
  524. exprasmlist^.concat(new(pai68k,op_csymbol_reg(A_MOVE,S_L,
  525. newcsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,0),R_A5)));
  526. concat_external(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,EXT_NEAR);
  527. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  528. end
  529. else
  530. { this is a member call, so A5 isn't modfied }
  531. loada5:=false;
  532. if not(is_con_or_destructor and
  533. pobjectdef(p^.methodpointer^.resulttype)^.isclass and
  534. assigned(aktprocsym) and
  535. ((aktprocsym^.definition^.options and
  536. (poconstructor or podestructor))<>0)) then
  537. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  538. { if an inherited con- or destructor should be }
  539. { called in a con- or destructor then a warning }
  540. { will be made }
  541. { con- and destructors need a pointer to the vmt }
  542. if is_con_or_destructor and
  543. ((pobjectdef(p^.methodpointer^.resulttype)^.options and oo_is_class)=0) and
  544. assigned(aktprocsym) then
  545. begin
  546. if not ((aktprocsym^.definition^.options
  547. and (poconstructor or podestructor))<>0) then
  548. CGMessage(cg_w_member_cd_call_from_method);
  549. end;
  550. { con- and destructors need a pointer to the vmt }
  551. if is_con_or_destructor then
  552. begin
  553. { classes need the mem ! }
  554. if ((pobjectdef(p^.methodpointer^.resulttype)^.options and
  555. oo_is_class)=0) then
  556. push_int(0)
  557. else
  558. begin
  559. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,
  560. S_L,newcsymbol(pobjectdef(p^.methodpointer^.
  561. resulttype)^.vmt_mangledname,0))));
  562. concat_external(pobjectdef(p^.methodpointer^.resulttype)^.
  563. vmt_mangledname,EXT_NEAR);
  564. end;
  565. end;
  566. end;
  567. hnewn : begin
  568. { extended syntax of new }
  569. { A5 must be zero }
  570. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,0,R_A5)));
  571. emit_reg_reg(A_MOVE,S_L,R_A5, R_SPPUSH);
  572. { insert the vmt }
  573. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,S_L,
  574. newcsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,0))));
  575. concat_external(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,EXT_NEAR);
  576. extended_new:=true;
  577. end;
  578. hdisposen : begin
  579. secondpass(p^.methodpointer);
  580. { destructor with extended syntax called from dispose }
  581. { hdisposen always deliver LOC_REFRENZ }
  582. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,
  583. newreference(p^.methodpointer^.location.reference),R_A5)));
  584. del_reference(p^.methodpointer^.location.reference);
  585. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  586. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,S_L,
  587. newcsymbol(pobjectdef
  588. (p^.methodpointer^.resulttype)^.vmt_mangledname,0))));
  589. concat_external(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,EXT_NEAR);
  590. end;
  591. else
  592. begin
  593. { call to a instance member }
  594. if (p^.symtable^.symtabletype<>withsymtable) then
  595. begin
  596. secondpass(p^.methodpointer);
  597. case p^.methodpointer^.location.loc of
  598. LOC_REGISTER :
  599. begin
  600. ungetregister32(p^.methodpointer^.location.register);
  601. emit_reg_reg(A_MOVE,S_L,p^.methodpointer^.location.register,R_A5);
  602. end;
  603. else
  604. begin
  605. if (p^.methodpointer^.resulttype^.deftype=objectdef) and
  606. pobjectdef(p^.methodpointer^.resulttype)^.isclass then
  607. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  608. newreference(p^.methodpointer^.location.reference),R_A5)))
  609. else
  610. Begin
  611. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,
  612. newreference(p^.methodpointer^.location.reference),R_A5)));
  613. end;
  614. del_reference(p^.methodpointer^.location.reference);
  615. end;
  616. end;
  617. end;
  618. { when calling a class method, we have
  619. to load ESI with the VMT !
  620. But that's wrong, if we call a class method via self
  621. }
  622. if ((p^.procdefinition^.options and poclassmethod)<>0)
  623. and not(p^.methodpointer^.treetype=selfn) then
  624. begin
  625. { class method needs current VMT }
  626. new(r);
  627. reset_reference(r^);
  628. r^.base:=R_A5;
  629. r^.offset:= p^.procdefinition^._class^.vmt_offset;
  630. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_A5)));
  631. end;
  632. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  633. if is_con_or_destructor then
  634. begin
  635. { classes don't get a VMT pointer pushed }
  636. if (p^.methodpointer^.resulttype^.deftype=objectdef) and
  637. not(pobjectdef(p^.methodpointer^.resulttype)^.isclass) then
  638. begin
  639. if ((p^.procdefinition^.options and poconstructor)<>0) then
  640. begin
  641. { it's no bad idea, to insert the VMT }
  642. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,S_L,
  643. newcsymbol(pobjectdef(
  644. p^.methodpointer^.resulttype)^.vmt_mangledname,0))));
  645. concat_external(pobjectdef(
  646. p^.methodpointer^.resulttype)^.vmt_mangledname,EXT_NEAR);
  647. end
  648. { destructors haven't to dispose the instance, if this is }
  649. { a direct call }
  650. else
  651. push_int(0);
  652. end;
  653. end;
  654. end;
  655. end;
  656. end
  657. else
  658. begin
  659. if ((p^.procdefinition^.options and poclassmethod)<>0) and
  660. not(
  661. assigned(aktprocsym) and
  662. ((aktprocsym^.definition^.options and poclassmethod)<>0)
  663. ) then
  664. begin
  665. { class method needs current VMT }
  666. new(r);
  667. reset_reference(r^);
  668. r^.base:=R_A5;
  669. r^.offset:= p^.procdefinition^._class^.vmt_offset;
  670. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_A5)));
  671. end
  672. else
  673. begin
  674. { member call, A5 isn't modified }
  675. loada5:=false;
  676. end;
  677. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  678. { but a con- or destructor here would probably almost }
  679. { always be placed wrong }
  680. if is_con_or_destructor then
  681. begin
  682. CGMessage(cg_w_member_cd_call_from_method);
  683. { not insert VMT pointer } { VMT-Zeiger nicht eintragen }
  684. push_int(0);
  685. end;
  686. end;
  687. end;
  688. { push base pointer ?}
  689. if (lexlevel>=normal_function_level) and assigned(pprocdef(p^.procdefinition)^.parast) and
  690. ((p^.procdefinition^.parast^.symtablelevel)>normal_function_level) then
  691. begin
  692. { if we call a nested function in a method, we must }
  693. { push also SELF! }
  694. { THAT'S NOT TRUE, we have to load ESI via frame pointer }
  695. { access }
  696. {
  697. begin
  698. loadesi:=false;
  699. exprasmlist^.concat(new(pai68k,op_reg(A_PUSH,S_L,R_ESI)));
  700. end;
  701. }
  702. if lexlevel=(p^.procdefinition^.parast^.symtablelevel) then
  703. begin
  704. new(r);
  705. reset_reference(r^);
  706. r^.offset:=procinfo.framepointer_offset;
  707. r^.base:=procinfo.framepointer;
  708. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_SPPUSH)))
  709. end
  710. { this is only true if the difference is one !!
  711. but it cannot be more !! }
  712. else if lexlevel=(p^.procdefinition^.parast^.symtablelevel)-1 then
  713. begin
  714. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,procinfo.framepointer,R_SPPUSH)))
  715. end
  716. else if lexlevel>(p^.procdefinition^.parast^.symtablelevel) then
  717. begin
  718. hregister:=getaddressreg;
  719. new(r);
  720. reset_reference(r^);
  721. r^.offset:=procinfo.framepointer_offset;
  722. r^.base:=procinfo.framepointer;
  723. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,hregister)));
  724. for i:=(p^.procdefinition^.parast^.symtablelevel) to lexlevel-1 do
  725. begin
  726. new(r);
  727. reset_reference(r^);
  728. {we should get the correct frame_pointer_offset at each level
  729. how can we do this !!! }
  730. r^.offset:=procinfo.framepointer_offset;
  731. r^.base:=hregister;
  732. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,hregister)));
  733. end;
  734. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,hregister,R_SPPUSH)));
  735. ungetregister32(hregister);
  736. end
  737. else
  738. internalerror(25000);
  739. end;
  740. { exported methods should be never called direct }
  741. if (p^.procdefinition^.options and poexports)<>0 then
  742. CGMessage(cg_e_dont_call_exported_direct);
  743. if ((p^.procdefinition^.options and povirtualmethod)<>0) and
  744. not(no_virtual_call) then
  745. begin
  746. { static functions contain the vmt_address in ESI }
  747. { also class methods }
  748. if assigned(aktprocsym) then
  749. begin
  750. if ((aktprocsym^.properties and sp_static)<>0) or
  751. ((aktprocsym^.definition^.options and poclassmethod)<>0) or
  752. ((p^.procdefinition^.options and postaticmethod)<>0) or
  753. { A5 is already loaded }
  754. ((p^.procdefinition^.options and poclassmethod)<>0)then
  755. begin
  756. new(r);
  757. reset_reference(r^);
  758. r^.base:=R_a5;
  759. end
  760. else
  761. begin
  762. new(r);
  763. reset_reference(r^);
  764. r^.base:=R_a5;
  765. r^.offset:= p^.procdefinition^._class^.vmt_offset;
  766. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_a0)));
  767. new(r);
  768. reset_reference(r^);
  769. r^.base:=R_a0;
  770. end;
  771. end
  772. else
  773. begin
  774. new(r);
  775. reset_reference(r^);
  776. r^.base:=R_a5;
  777. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_a0)));
  778. new(r);
  779. reset_reference(r^);
  780. r^.base:=R_a0;
  781. end;
  782. if p^.procdefinition^.extnumber=-1 then
  783. internalerror($Da);
  784. r^.offset:=p^.procdefinition^.extnumber*4+12;
  785. if (cs_check_range in aktlocalswitches) then
  786. begin
  787. { If the base is already A0, the no instruction will }
  788. { be emitted! }
  789. emit_reg_reg(A_MOVE,S_L,r^.base,R_A0);
  790. emitcall('FPC_CHECK_OBJECT',true);
  791. end;
  792. { This was wrong we must then load the address into the }
  793. { register a0 and/or a5 }
  794. { Because doing an indirect call with offset is NOT }
  795. { allowed on the m68k! }
  796. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(r^),R_A0)));
  797. { clear the reference }
  798. reset_reference(r^);
  799. r^.base := R_A0;
  800. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,r)));
  801. end
  802. else if (p^.procdefinition^.options and popalmossyscall)<>0 then
  803. begin
  804. exprasmlist^.concat(new(pai68k,op_const(A_TRAP,S_NO,15)));
  805. exprasmlist^.concat(new(pai_const,init_16bit(p^.procdefinition^.extnumber)));
  806. end
  807. else
  808. emitcall(p^.procdefinition^.mangledname,
  809. (p^.symtableproc^.symtabletype=unitsymtable) or
  810. ((p^.symtableproc^.symtabletype=objectsymtable) and
  811. (pobjectdef(p^.symtableproc^.defowner)^.owner^.symtabletype=unitsymtable))or
  812. ((p^.symtableproc^.symtabletype=withsymtable) and
  813. (pobjectdef(p^.symtableproc^.defowner)^.owner^.symtabletype=unitsymtable)));
  814. if ((p^.procdefinition^.options and poclearstack)<>0) then
  815. begin
  816. if (pushedparasize > 0) and (pushedparasize < 9) then
  817. { restore the stack, to its initial value }
  818. exprasmlist^.concat(new(pai68k,op_const_reg(A_ADDQ,S_L,pushedparasize,R_SP)))
  819. else
  820. { restore the stack, to its initial value }
  821. exprasmlist^.concat(new(pai68k,op_const_reg(A_ADDA,S_L,pushedparasize,R_SP)));
  822. end;
  823. end
  824. else
  825. begin
  826. secondpass(p^.right);
  827. case p^.right^.location.loc of
  828. LOC_REGISTER,
  829. LOC_CREGISTER : begin
  830. if p^.right^.location.register in [R_D0..R_D7] then
  831. begin
  832. reg := getaddressreg;
  833. emit_reg_reg(A_MOVE,S_L,p^.right^.location.register,reg);
  834. new(ref);
  835. reset_reference(ref^);
  836. ref^.base := reg;
  837. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,ref)));
  838. ungetregister(reg);
  839. end
  840. else
  841. begin
  842. new(ref);
  843. reset_reference(ref^);
  844. ref^.base := p^.right^.location.register;
  845. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,ref)));
  846. end;
  847. ungetregister32(p^.right^.location.register);
  848. end
  849. else
  850. begin
  851. if assigned(p^.right^.location.reference.symbol) then
  852. { Here we have a symbolic name to the routine, so solve }
  853. { problem by loading the address first, and then emitting }
  854. { the call. }
  855. begin
  856. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  857. newreference(p^.right^.location.reference),R_A1)));
  858. new(ref);
  859. reset_reference(ref^);
  860. ref^.base := R_A1;
  861. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,ref)));
  862. end
  863. else
  864. begin
  865. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  866. newreference(p^.right^.location.reference),R_A1)));
  867. new(ref);
  868. reset_reference(ref^);
  869. ref^.base := R_A1;
  870. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,ref)));
  871. end;
  872. del_reference(p^.right^.location.reference);
  873. end;
  874. end;
  875. end;
  876. dont_call:
  877. pushedparasize:=oldpushedparasize;
  878. unused:=unusedregisters;
  879. { handle function results }
  880. if p^.resulttype<>pdef(voiddef) then
  881. begin
  882. { a contructor could be a function with boolean result }
  883. if (p^.right=nil) and
  884. ((p^.procdefinition^.options and poconstructor)<>0) and
  885. { quick'n'dirty check if it is a class or an object }
  886. (p^.resulttype^.deftype=orddef) then
  887. begin
  888. p^.location.loc:=LOC_FLAGS;
  889. p^.location.resflags:=F_NE;
  890. if extended_new then
  891. begin
  892. {$ifdef test_dest_loc}
  893. if dest_loc_known and (dest_loc_tree=p) then
  894. mov_reg_to_dest(p,S_L,R_EAX)
  895. else
  896. {$endif test_dest_loc}
  897. hregister:=getregister32;
  898. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  899. p^.location.register:=hregister;
  900. end;
  901. end
  902. { structed results are easy to handle.... }
  903. else if ret_in_param(p^.resulttype) then
  904. begin
  905. p^.location.loc:=LOC_MEM;
  906. stringdispose(p^.location.reference.symbol);
  907. p^.location.reference:=funcretref;
  908. end
  909. else
  910. begin
  911. if (p^.resulttype^.deftype=orddef) then
  912. begin
  913. p^.location.loc:=LOC_REGISTER;
  914. case porddef(p^.resulttype)^.typ of
  915. s32bit,u32bit :
  916. begin
  917. hregister:=getregister32;
  918. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  919. p^.location.register:=hregister;
  920. end;
  921. uchar,u8bit,bool8bit,s8bit :
  922. begin
  923. hregister:=getregister32;
  924. emit_reg_reg(A_MOVE,S_B,R_D0,hregister);
  925. p^.location.register:=hregister;
  926. end;
  927. s16bit,u16bit :
  928. begin
  929. hregister:=getregister32;
  930. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  931. p^.location.register:=hregister;
  932. end;
  933. else internalerror(7);
  934. end
  935. end
  936. else if (p^.resulttype^.deftype=floatdef) then
  937. case pfloatdef(p^.resulttype)^.typ of
  938. f32bit :
  939. begin
  940. p^.location.loc:=LOC_REGISTER;
  941. hregister:=getregister32;
  942. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  943. p^.location.register:=hregister;
  944. end;
  945. s32real : Begin
  946. p^.location.loc:=LOC_FPU;
  947. hregister:=getregister32;
  948. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  949. p^.location.fpureg:=hregister;
  950. end;
  951. s64bit,s64real,s80real: begin
  952. if cs_fp_emulation in aktmoduleswitches then
  953. begin
  954. p^.location.loc:=LOC_FPU;
  955. hregister:=getregister32;
  956. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  957. p^.location.fpureg:=hregister;
  958. end
  959. else
  960. begin
  961. { TRUE FPU mode }
  962. p^.location.loc:=LOC_FPU;
  963. { on exit of function result in R_FP0 }
  964. p^.location.fpureg:=R_FP0;
  965. end;
  966. end;
  967. else
  968. begin
  969. p^.location.loc:=LOC_FPU;
  970. p^.location.fpureg:=R_FP0;
  971. end;
  972. end {end case }
  973. else
  974. begin
  975. p^.location.loc:=LOC_REGISTER;
  976. hregister:=getregister32;
  977. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  978. p^.location.register:=hregister;
  979. end;
  980. end;
  981. end;
  982. { perhaps i/o check ? }
  983. if iolabel<>nil then
  984. begin
  985. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,S_L,newcsymbol(lab2str(iolabel),0))));
  986. emitcall('FPC_IOCHECK',true);
  987. end;
  988. { restore registers }
  989. popusedregisters(pushed);
  990. { at last, restore instance pointer (SELF) }
  991. if loada5 then
  992. maybe_loada5;
  993. pp:=params;
  994. while assigned(pp) do
  995. begin
  996. if assigned(pp^.left) then
  997. if (pp^.left^.location.loc=LOC_REFERENCE) or
  998. (pp^.left^.location.loc=LOC_MEM) then
  999. ungetiftemp(pp^.left^.location.reference);
  1000. pp:=pp^.right;
  1001. end;
  1002. disposetree(params);
  1003. end;
  1004. {*****************************************************************************
  1005. SecondProcInlineN
  1006. *****************************************************************************}
  1007. procedure secondprocinline(var p : ptree);
  1008. begin
  1009. InternalError(132421);
  1010. end;
  1011. end.
  1012. {
  1013. $Log$
  1014. Revision 1.16 1998-11-13 15:40:15 pierre
  1015. + added -Se in Makefile cvstest target
  1016. + lexlevel cleanup
  1017. normal_function_level main_program_level and unit_init_level defined
  1018. * tins_cache grown to A_EMMS (gave range check error in asm readers)
  1019. (test added in code !)
  1020. * -Un option was wrong
  1021. * _FAIL and _SELF only keyword inside
  1022. constructors and methods respectively
  1023. Revision 1.15 1998/11/12 11:19:41 pierre
  1024. * fix for first line of function break
  1025. Revision 1.14 1998/10/21 15:12:51 pierre
  1026. * bug fix for IOCHECK inside a procedure with iocheck modifier
  1027. * removed the GPF for unexistant overloading
  1028. (firstcall was called with procedinition=nil !)
  1029. * changed typen to what Florian proposed
  1030. gentypenode(p : pdef) sets the typenodetype field
  1031. and resulttype is only set if inside bt_type block !
  1032. Revision 1.13 1998/10/20 08:06:45 pierre
  1033. * several memory corruptions due to double freemem solved
  1034. => never use p^.loc.location:=p^.left^.loc.location;
  1035. + finally I added now by default
  1036. that ra386dir translates global and unit symbols
  1037. + added a first field in tsymtable and
  1038. a nextsym field in tsym
  1039. (this allows to obtain ordered type info for
  1040. records and objects in gdb !)
  1041. Revision 1.12 1998/10/19 08:54:53 pierre
  1042. * wrong stabs info corrected once again !!
  1043. + variable vmt offset with vmt field only if required
  1044. implemented now !!!
  1045. Revision 1.11 1998/10/16 13:12:46 pierre
  1046. * added vmt_offsets in destructors code also !!!
  1047. * vmt_offset code for m68k
  1048. Revision 1.10 1998/10/15 12:41:16 pierre
  1049. * last memory leaks found when compiler
  1050. a native atari compiler fixed
  1051. Revision 1.9 1998/10/14 11:28:16 florian
  1052. * emitpushreferenceaddress gets now the asmlist as parameter
  1053. * m68k version compiles with -duseansistrings
  1054. Revision 1.8 1998/10/13 16:50:04 pierre
  1055. * undid some changes of Peter that made the compiler wrong
  1056. for m68k (I had to reinsert some ifdefs)
  1057. * removed several memory leaks under m68k
  1058. * removed the meory leaks for assembler readers
  1059. * cross compiling shoud work again better
  1060. ( crosscompiling sysamiga works
  1061. but as68k still complain about some code !)
  1062. Revision 1.7 1998/10/13 08:19:27 pierre
  1063. + source_os is now set correctly for cross-processor compilers
  1064. (tos contains all target_infos and
  1065. we use CPU86 and CPU68 conditionnals to
  1066. get the source operating system
  1067. this only works if you do not undefine
  1068. the source target !!)
  1069. * several cg68k memory leaks fixed
  1070. + started to change the code so that it should be possible to have
  1071. a complete compiler (both for m68k and i386 !!)
  1072. Revision 1.6 1998/09/20 12:26:38 peter
  1073. * merged fixes
  1074. Revision 1.5 1998/09/17 09:42:22 peter
  1075. + pass_2 for cg386
  1076. * Message() -> CGMessage() for pass_1/pass_2
  1077. Revision 1.4 1998/09/14 10:43:55 peter
  1078. * all internal RTL functions start with FPC_
  1079. Revision 1.3.2.1 1998/09/20 12:20:09 peter
  1080. * Fixed stack not on 4 byte boundary when doing a call
  1081. Revision 1.3 1998/09/04 08:41:43 peter
  1082. * updated some error CGMessages
  1083. Revision 1.2 1998/09/01 12:47:59 peter
  1084. * use pdef^.size instead of orddef^.typ
  1085. Revision 1.1 1998/09/01 09:07:09 peter
  1086. * m68k fixes, splitted cg68k like cgi386
  1087. }