cg68kcal.pas 59 KB

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