cg68kcal.pas 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  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(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(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(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. truelabel:=otlabel;
  363. falselabel:=oflabel;
  364. { push from right to left }
  365. if not push_from_left_to_right and assigned(p^.right) then
  366. secondcallparan(p^.right,defcoll^.next,push_from_left_to_right);
  367. end;
  368. {*****************************************************************************
  369. SecondCallN
  370. *****************************************************************************}
  371. procedure secondcalln(var p : ptree);
  372. var
  373. unusedregisters : tregisterset;
  374. pushed : tpushed;
  375. funcretref : treference;
  376. hregister : tregister;
  377. oldpushedparasize : longint;
  378. { true if a5 must be loaded again after the subroutine }
  379. loada5 : boolean;
  380. { true if a virtual method must be called directly }
  381. no_virtual_call : boolean;
  382. { true if we produce a con- or destrutor in a call }
  383. is_con_or_destructor : boolean;
  384. { true if a constructor is called again }
  385. extended_new : boolean;
  386. { adress returned from an I/O-error }
  387. iolabel : plabel;
  388. { lexlevel count }
  389. i : longint;
  390. { help reference pointer }
  391. r : preference;
  392. pp,params : ptree;
  393. { temp register allocation }
  394. reg: tregister;
  395. { help reference pointer }
  396. ref: preference;
  397. label
  398. dont_call;
  399. begin
  400. extended_new:=false;
  401. iolabel:=nil;
  402. loada5:=true;
  403. no_virtual_call:=false;
  404. unusedregisters:=unused;
  405. if not assigned(p^.procdefinition) then
  406. exit;
  407. { only if no proc var }
  408. if not(assigned(p^.right)) then
  409. is_con_or_destructor:=((p^.procdefinition^.options and poconstructor)<>0)
  410. or ((p^.procdefinition^.options and podestructor)<>0);
  411. { proc variables destroy all registers }
  412. if (p^.right=nil) and
  413. { virtual methods too }
  414. ((p^.procdefinition^.options and povirtualmethod)=0) then
  415. begin
  416. if ((p^.procdefinition^.options and poiocheck)<>0)
  417. and (cs_check_io in aktlocalswitches) then
  418. begin
  419. getlabel(iolabel);
  420. emitl(A_LABEL,iolabel);
  421. end
  422. else iolabel:=nil;
  423. { save all used registers }
  424. pushusedregisters(pushed,p^.procdefinition^.usedregisters);
  425. { give used registers through }
  426. usedinproc:=usedinproc or p^.procdefinition^.usedregisters;
  427. end
  428. else
  429. begin
  430. pushusedregisters(pushed,$ffff);
  431. usedinproc:=$ffff;
  432. { no IO check for methods and procedure variables }
  433. iolabel:=nil;
  434. end;
  435. { generate the code for the parameter and push them }
  436. oldpushedparasize:=pushedparasize;
  437. pushedparasize:=0;
  438. if (p^.resulttype<>pdef(voiddef)) and
  439. ret_in_param(p^.resulttype) then
  440. begin
  441. funcretref.symbol:=nil;
  442. {$ifdef test_dest_loc}
  443. if dest_loc_known and (dest_loc_tree=p) and
  444. (dest_loc.loc in [LOC_REFERENCE,LOC_MEM]) then
  445. begin
  446. funcretref:=dest_loc.reference;
  447. if assigned(dest_loc.reference.symbol) then
  448. funcretref.symbol:=stringdup(dest_loc.reference.symbol^);
  449. in_dest_loc:=true;
  450. end
  451. else
  452. {$endif test_dest_loc}
  453. gettempofsizereference(p^.procdefinition^.retdef^.size,funcretref);
  454. end;
  455. if assigned(p^.left) then
  456. begin
  457. pushedparasize:=0;
  458. { be found elsewhere }
  459. if assigned(p^.right) then
  460. secondcallparan(p^.left,pprocvardef(p^.right^.resulttype)^.para1,
  461. (p^.procdefinition^.options and poleftright)<>0)
  462. else
  463. secondcallparan(p^.left,p^.procdefinition^.para1,
  464. (p^.procdefinition^.options and poleftright)<>0);
  465. end;
  466. params:=p^.left;
  467. p^.left:=nil;
  468. if ret_in_param(p^.resulttype) then
  469. begin
  470. emitpushreferenceaddr(funcretref);
  471. inc(pushedparasize,4);
  472. end;
  473. { overloaded operator have no symtable }
  474. if (p^.right=nil) then
  475. begin
  476. { push self }
  477. if assigned(p^.symtable) and
  478. (p^.symtable^.symtabletype=withsymtable) then
  479. begin
  480. { dirty trick to avoid the secondcall below }
  481. p^.methodpointer:=genzeronode(callparan);
  482. p^.methodpointer^.location.loc:=LOC_REGISTER;
  483. p^.methodpointer^.location.register:=R_A5;
  484. { make a reference }
  485. new(r);
  486. reset_reference(r^);
  487. r^.offset:=p^.symtable^.datasize;
  488. r^.base:=procinfo.framepointer;
  489. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_A5)));
  490. end;
  491. { push self }
  492. if assigned(p^.symtable) and
  493. ((p^.symtable^.symtabletype=objectsymtable) or
  494. (p^.symtable^.symtabletype=withsymtable)) then
  495. begin
  496. if assigned(p^.methodpointer) then
  497. begin
  498. case p^.methodpointer^.treetype of
  499. typen : begin
  500. { direct call to inherited method }
  501. if (p^.procdefinition^.options and poabstractmethod)<>0 then
  502. begin
  503. CGMessage(cg_e_cant_call_abstract_method);
  504. goto dont_call;
  505. end;
  506. { generate no virtual call }
  507. no_virtual_call:=true;
  508. if (p^.symtableprocentry^.properties and sp_static)<>0 then
  509. begin
  510. { well lets put the VMT address directly into a5 }
  511. { it is kind of dirty but that is the simplest }
  512. { way to accept virtual static functions (PM) }
  513. loada5:=true;
  514. exprasmlist^.concat(new(pai68k,op_csymbol_reg(A_MOVE,S_L,
  515. newcsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,0),R_A5)));
  516. concat_external(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,EXT_NEAR);
  517. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  518. end
  519. else
  520. { this is a member call, so A5 isn't modfied }
  521. loada5:=false;
  522. if not(is_con_or_destructor and
  523. pobjectdef(p^.methodpointer^.resulttype)^.isclass and
  524. assigned(aktprocsym) and
  525. ((aktprocsym^.definition^.options and
  526. (poconstructor or podestructor))<>0)) then
  527. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  528. { if an inherited con- or destructor should be }
  529. { called in a con- or destructor then a warning }
  530. { will be made }
  531. { con- and destructors need a pointer to the vmt }
  532. if is_con_or_destructor and
  533. ((pobjectdef(p^.methodpointer^.resulttype)^.options and oois_class)=0) and
  534. assigned(aktprocsym) then
  535. begin
  536. if not ((aktprocsym^.definition^.options
  537. and (poconstructor or podestructor))<>0) then
  538. CGMessage(cg_w_member_cd_call_from_method);
  539. end;
  540. { con- and destructors need a pointer to the vmt }
  541. if is_con_or_destructor then
  542. begin
  543. { classes need the mem ! }
  544. if ((pobjectdef(p^.methodpointer^.resulttype)^.options and
  545. oois_class)=0) then
  546. push_int(0)
  547. else
  548. begin
  549. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,
  550. S_L,newcsymbol(pobjectdef(p^.methodpointer^.
  551. resulttype)^.vmt_mangledname,0))));
  552. concat_external(pobjectdef(p^.methodpointer^.resulttype)^.
  553. vmt_mangledname,EXT_NEAR);
  554. end;
  555. end;
  556. end;
  557. hnewn : begin
  558. { extended syntax of new }
  559. { A5 must be zero }
  560. exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,0,R_A5)));
  561. emit_reg_reg(A_MOVE,S_L,R_A5, R_SPPUSH);
  562. { insert the vmt }
  563. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,S_L,
  564. newcsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,0))));
  565. concat_external(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,EXT_NEAR);
  566. extended_new:=true;
  567. end;
  568. hdisposen : begin
  569. secondpass(p^.methodpointer);
  570. { destructor with extended syntax called from dispose }
  571. { hdisposen always deliver LOC_REFRENZ }
  572. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,
  573. newreference(p^.methodpointer^.location.reference),R_A5)));
  574. del_reference(p^.methodpointer^.location.reference);
  575. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  576. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,S_L,
  577. newcsymbol(pobjectdef
  578. (p^.methodpointer^.resulttype)^.vmt_mangledname,0))));
  579. concat_external(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,EXT_NEAR);
  580. end;
  581. else
  582. begin
  583. { call to a instance member }
  584. if (p^.symtable^.symtabletype<>withsymtable) then
  585. begin
  586. secondpass(p^.methodpointer);
  587. case p^.methodpointer^.location.loc of
  588. LOC_REGISTER :
  589. begin
  590. ungetregister32(p^.methodpointer^.location.register);
  591. emit_reg_reg(A_MOVE,S_L,p^.methodpointer^.location.register,R_A5);
  592. end;
  593. else
  594. begin
  595. if (p^.methodpointer^.resulttype^.deftype=objectdef) and
  596. pobjectdef(p^.methodpointer^.resulttype)^.isclass then
  597. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  598. newreference(p^.methodpointer^.location.reference),R_A5)))
  599. else
  600. Begin
  601. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,
  602. newreference(p^.methodpointer^.location.reference),R_A5)));
  603. end;
  604. del_reference(p^.methodpointer^.location.reference);
  605. end;
  606. end;
  607. end;
  608. { when calling a class method, we have
  609. to load ESI with the VMT !
  610. But that's wrong, if we call a class method via self
  611. }
  612. if ((p^.procdefinition^.options and poclassmethod)<>0)
  613. and not(p^.methodpointer^.treetype=selfn) then
  614. begin
  615. { class method needs current VMT }
  616. new(r);
  617. reset_reference(r^);
  618. r^.base:=R_A5;
  619. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_A5)));
  620. end;
  621. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  622. if is_con_or_destructor then
  623. begin
  624. { classes don't get a VMT pointer pushed }
  625. if (p^.methodpointer^.resulttype^.deftype=objectdef) and
  626. not(pobjectdef(p^.methodpointer^.resulttype)^.isclass) then
  627. begin
  628. if ((p^.procdefinition^.options and poconstructor)<>0) then
  629. begin
  630. { it's no bad idea, to insert the VMT }
  631. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,S_L,
  632. newcsymbol(pobjectdef(
  633. p^.methodpointer^.resulttype)^.vmt_mangledname,0))));
  634. concat_external(pobjectdef(
  635. p^.methodpointer^.resulttype)^.vmt_mangledname,EXT_NEAR);
  636. end
  637. { destructors haven't to dispose the instance, if this is }
  638. { a direct call }
  639. else
  640. push_int(0);
  641. end;
  642. end;
  643. end;
  644. end;
  645. end
  646. else
  647. begin
  648. if ((p^.procdefinition^.options and poclassmethod)<>0) and
  649. not(
  650. assigned(aktprocsym) and
  651. ((aktprocsym^.definition^.options and poclassmethod)<>0)
  652. ) then
  653. begin
  654. { class method needs current VMT }
  655. new(r);
  656. reset_reference(r^);
  657. r^.base:=R_A5;
  658. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_A5)));
  659. end
  660. else
  661. begin
  662. { member call, A5 isn't modified }
  663. loada5:=false;
  664. end;
  665. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  666. { but a con- or destructor here would probably almost }
  667. { always be placed wrong }
  668. if is_con_or_destructor then
  669. begin
  670. CGMessage(cg_w_member_cd_call_from_method);
  671. { not insert VMT pointer } { VMT-Zeiger nicht eintragen }
  672. push_int(0);
  673. end;
  674. end;
  675. end;
  676. { push base pointer ?}
  677. if (lexlevel>1) and assigned(pprocdef(p^.procdefinition)^.parast) and
  678. ((p^.procdefinition^.parast^.symtablelevel)>2) then
  679. begin
  680. { if we call a nested function in a method, we must }
  681. { push also SELF! }
  682. { THAT'S NOT TRUE, we have to load ESI via frame pointer }
  683. { access }
  684. {
  685. begin
  686. loadesi:=false;
  687. exprasmlist^.concat(new(pai68k,op_reg(A_PUSH,S_L,R_ESI)));
  688. end;
  689. }
  690. if lexlevel=(p^.procdefinition^.parast^.symtablelevel) then
  691. begin
  692. new(r);
  693. reset_reference(r^);
  694. r^.offset:=procinfo.framepointer_offset;
  695. r^.base:=procinfo.framepointer;
  696. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_SPPUSH)))
  697. end
  698. { this is only true if the difference is one !!
  699. but it cannot be more !! }
  700. else if lexlevel=(p^.procdefinition^.parast^.symtablelevel)-1 then
  701. begin
  702. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,procinfo.framepointer,R_SPPUSH)))
  703. end
  704. else if lexlevel>(p^.procdefinition^.parast^.symtablelevel) then
  705. begin
  706. hregister:=getaddressreg;
  707. new(r);
  708. reset_reference(r^);
  709. r^.offset:=procinfo.framepointer_offset;
  710. r^.base:=procinfo.framepointer;
  711. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,hregister)));
  712. for i:=(p^.procdefinition^.parast^.symtablelevel) to lexlevel-1 do
  713. begin
  714. new(r);
  715. reset_reference(r^);
  716. {we should get the correct frame_pointer_offset at each level
  717. how can we do this !!! }
  718. r^.offset:=procinfo.framepointer_offset;
  719. r^.base:=hregister;
  720. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,hregister)));
  721. end;
  722. exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,hregister,R_SPPUSH)));
  723. ungetregister32(hregister);
  724. end
  725. else
  726. internalerror(25000);
  727. end;
  728. { exported methods should be never called direct }
  729. if (p^.procdefinition^.options and poexports)<>0 then
  730. CGMessage(cg_e_dont_call_exported_direct);
  731. if ((p^.procdefinition^.options and povirtualmethod)<>0) and
  732. not(no_virtual_call) then
  733. begin
  734. { static functions contain the vmt_address in ESI }
  735. { also class methods }
  736. if assigned(aktprocsym) then
  737. begin
  738. if ((aktprocsym^.properties and sp_static)<>0) or
  739. ((aktprocsym^.definition^.options and poclassmethod)<>0) or
  740. ((p^.procdefinition^.options and postaticmethod)<>0) or
  741. { A5 is already loaded }
  742. ((p^.procdefinition^.options and poclassmethod)<>0)then
  743. begin
  744. new(r);
  745. reset_reference(r^);
  746. r^.base:=R_a5;
  747. end
  748. else
  749. begin
  750. new(r);
  751. reset_reference(r^);
  752. r^.base:=R_a5;
  753. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_a0)));
  754. new(r);
  755. reset_reference(r^);
  756. r^.base:=R_a0;
  757. end;
  758. end
  759. else
  760. begin
  761. new(r);
  762. reset_reference(r^);
  763. r^.base:=R_a5;
  764. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,R_a0)));
  765. new(r);
  766. reset_reference(r^);
  767. r^.base:=R_a0;
  768. end;
  769. if p^.procdefinition^.extnumber=-1 then
  770. internalerror($Da);
  771. r^.offset:=p^.procdefinition^.extnumber*4+12;
  772. if (cs_check_range in aktlocalswitches) then
  773. begin
  774. { If the base is already A0, the no instruction will }
  775. { be emitted! }
  776. emit_reg_reg(A_MOVE,S_L,r^.base,R_A0);
  777. emitcall('FPC_CHECK_OBJECT',true);
  778. end;
  779. { This was wrong we must then load the address into the }
  780. { register a0 and/or a5 }
  781. { Because doing an indirect call with offset is NOT }
  782. { allowed on the m68k! }
  783. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(r^),R_A0)));
  784. { clear the reference }
  785. reset_reference(r^);
  786. r^.base := R_A0;
  787. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,r)));
  788. end
  789. else if (p^.procdefinition^.options and popalmossyscall)<>0 then
  790. begin
  791. exprasmlist^.concat(new(pai68k,op_const(A_TRAP,S_NO,15)));
  792. exprasmlist^.concat(new(pai_const,init_16bit(p^.procdefinition^.extnumber)));
  793. end
  794. else
  795. emitcall(p^.procdefinition^.mangledname,
  796. p^.symtableproc^.symtabletype=unitsymtable);
  797. if ((p^.procdefinition^.options and poclearstack)<>0) then
  798. begin
  799. if (pushedparasize > 0) and (pushedparasize < 9) then
  800. { restore the stack, to its initial value }
  801. exprasmlist^.concat(new(pai68k,op_const_reg(A_ADDQ,S_L,pushedparasize,R_SP)))
  802. else
  803. { restore the stack, to its initial value }
  804. exprasmlist^.concat(new(pai68k,op_const_reg(A_ADDA,S_L,pushedparasize,R_SP)));
  805. end;
  806. end
  807. else
  808. begin
  809. secondpass(p^.right);
  810. case p^.right^.location.loc of
  811. LOC_REGISTER,
  812. LOC_CREGISTER : begin
  813. if p^.right^.location.register in [R_D0..R_D7] then
  814. begin
  815. reg := getaddressreg;
  816. emit_reg_reg(A_MOVE,S_L,p^.right^.location.register,reg);
  817. new(ref);
  818. reset_reference(ref^);
  819. ref^.base := reg;
  820. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,ref)));
  821. ungetregister(reg);
  822. end
  823. else
  824. begin
  825. new(ref);
  826. reset_reference(ref^);
  827. ref^.base := p^.right^.location.register;
  828. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,ref)));
  829. end;
  830. ungetregister32(p^.right^.location.register);
  831. end
  832. else
  833. begin
  834. if assigned(p^.right^.location.reference.symbol) then
  835. { Here we have a symbolic name to the routine, so solve }
  836. { problem by loading the address first, and then emitting }
  837. { the call. }
  838. begin
  839. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  840. newreference(p^.right^.location.reference),R_A1)));
  841. new(ref);
  842. reset_reference(ref^);
  843. ref^.base := R_A1;
  844. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,newreference(ref^))));
  845. end
  846. else
  847. begin
  848. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  849. newreference(p^.right^.location.reference),R_A1)));
  850. new(ref);
  851. reset_reference(ref^);
  852. ref^.base := R_A1;
  853. exprasmlist^.concat(new(pai68k,op_ref(A_JSR,S_NO,newreference(ref^))));
  854. end;
  855. del_reference(p^.right^.location.reference);
  856. end;
  857. end;
  858. end;
  859. dont_call:
  860. pushedparasize:=oldpushedparasize;
  861. unused:=unusedregisters;
  862. { handle function results }
  863. if p^.resulttype<>pdef(voiddef) then
  864. begin
  865. { a contructor could be a function with boolean result }
  866. if (p^.right=nil) and
  867. ((p^.procdefinition^.options and poconstructor)<>0) and
  868. { quick'n'dirty check if it is a class or an object }
  869. (p^.resulttype^.deftype=orddef) then
  870. begin
  871. p^.location.loc:=LOC_FLAGS;
  872. p^.location.resflags:=F_NE;
  873. if extended_new then
  874. begin
  875. {$ifdef test_dest_loc}
  876. if dest_loc_known and (dest_loc_tree=p) then
  877. mov_reg_to_dest(p,S_L,R_EAX)
  878. else
  879. {$endif test_dest_loc}
  880. hregister:=getregister32;
  881. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  882. p^.location.register:=hregister;
  883. end;
  884. end
  885. { structed results are easy to handle.... }
  886. else if ret_in_param(p^.resulttype) then
  887. begin
  888. p^.location.loc:=LOC_MEM;
  889. stringdispose(p^.location.reference.symbol);
  890. p^.location.reference:=funcretref;
  891. end
  892. else
  893. begin
  894. if (p^.resulttype^.deftype=orddef) then
  895. begin
  896. p^.location.loc:=LOC_REGISTER;
  897. case porddef(p^.resulttype)^.typ of
  898. s32bit,u32bit :
  899. begin
  900. hregister:=getregister32;
  901. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  902. p^.location.register:=hregister;
  903. end;
  904. uchar,u8bit,bool8bit,s8bit :
  905. begin
  906. hregister:=getregister32;
  907. emit_reg_reg(A_MOVE,S_B,R_D0,hregister);
  908. p^.location.register:=hregister;
  909. end;
  910. s16bit,u16bit :
  911. begin
  912. hregister:=getregister32;
  913. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  914. p^.location.register:=hregister;
  915. end;
  916. else internalerror(7);
  917. end
  918. end
  919. else if (p^.resulttype^.deftype=floatdef) then
  920. case pfloatdef(p^.resulttype)^.typ of
  921. f32bit :
  922. begin
  923. p^.location.loc:=LOC_REGISTER;
  924. hregister:=getregister32;
  925. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  926. p^.location.register:=hregister;
  927. end;
  928. s32real : Begin
  929. p^.location.loc:=LOC_FPU;
  930. hregister:=getregister32;
  931. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  932. p^.location.fpureg:=hregister;
  933. end;
  934. s64bit,s64real,s80real: begin
  935. if cs_fp_emulation in aktmoduleswitches then
  936. begin
  937. p^.location.loc:=LOC_FPU;
  938. hregister:=getregister32;
  939. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  940. p^.location.fpureg:=hregister;
  941. end
  942. else
  943. begin
  944. { TRUE FPU mode }
  945. p^.location.loc:=LOC_FPU;
  946. { on exit of function result in R_FP0 }
  947. p^.location.fpureg:=R_FP0;
  948. end;
  949. end;
  950. else
  951. begin
  952. p^.location.loc:=LOC_FPU;
  953. p^.location.fpureg:=R_FP0;
  954. end;
  955. end {end case }
  956. else
  957. begin
  958. p^.location.loc:=LOC_REGISTER;
  959. hregister:=getregister32;
  960. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  961. p^.location.register:=hregister;
  962. end;
  963. end;
  964. end;
  965. { perhaps i/o check ? }
  966. if iolabel<>nil then
  967. begin
  968. exprasmlist^.concat(new(pai68k,op_csymbol(A_PEA,S_L,newcsymbol(lab2str(iolabel),0))));
  969. emitcall('FPC_IOCHECK',true);
  970. end;
  971. { restore registers }
  972. popusedregisters(pushed);
  973. { at last, restore instance pointer (SELF) }
  974. if loada5 then
  975. maybe_loada5;
  976. pp:=params;
  977. while assigned(pp) do
  978. begin
  979. if assigned(pp^.left) then
  980. if (pp^.left^.location.loc=LOC_REFERENCE) or
  981. (pp^.left^.location.loc=LOC_MEM) then
  982. ungetiftemp(pp^.left^.location.reference);
  983. pp:=pp^.right;
  984. end;
  985. disposetree(params);
  986. end;
  987. {*****************************************************************************
  988. SecondProcInlineN
  989. *****************************************************************************}
  990. procedure secondprocinline(var p : ptree);
  991. begin
  992. InternalError(132421);
  993. end;
  994. end.
  995. {
  996. $Log$
  997. Revision 1.6 1998-09-20 12:26:38 peter
  998. * merged fixes
  999. Revision 1.5 1998/09/17 09:42:22 peter
  1000. + pass_2 for cg386
  1001. * Message() -> CGMessage() for pass_1/pass_2
  1002. Revision 1.4 1998/09/14 10:43:55 peter
  1003. * all internal RTL functions start with FPC_
  1004. Revision 1.3.2.1 1998/09/20 12:20:09 peter
  1005. * Fixed stack not on 4 byte boundary when doing a call
  1006. Revision 1.3 1998/09/04 08:41:43 peter
  1007. * updated some error CGMessages
  1008. Revision 1.2 1998/09/01 12:47:59 peter
  1009. * use pdef^.size instead of orddef^.typ
  1010. Revision 1.1 1998/09/01 09:07:09 peter
  1011. * m68k fixes, splitted cg68k like cgi386
  1012. }