cg68kcal.pas 61 KB

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