cg68kcal.pas 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 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. truelabel:=otlabel;
  370. falselabel:=oflabel;
  371. { push from right to left }
  372. if not push_from_left_to_right and assigned(p^.right) then
  373. secondcallparan(p^.right,defcoll^.next,push_from_left_to_right);
  374. end;
  375. {*****************************************************************************
  376. SecondCallN
  377. *****************************************************************************}
  378. procedure secondcalln(var p : ptree);
  379. var
  380. unusedregisters : tregisterset;
  381. pushed : tpushed;
  382. funcretref : treference;
  383. hregister : tregister;
  384. oldpushedparasize : longint;
  385. { true if a5 must be loaded again after the subroutine }
  386. loada5 : boolean;
  387. { true if a virtual method must be called directly }
  388. no_virtual_call : boolean;
  389. { true if we produce a con- or destrutor in a call }
  390. is_con_or_destructor : boolean;
  391. { true if a constructor is called again }
  392. extended_new : boolean;
  393. { adress returned from an I/O-error }
  394. iolabel : pasmlabel;
  395. { lexlevel count }
  396. i : longint;
  397. { help reference pointer }
  398. r : preference;
  399. pp,params : ptree;
  400. { temp register allocation }
  401. reg: tregister;
  402. { help reference pointer }
  403. ref: preference;
  404. label
  405. dont_call;
  406. begin
  407. extended_new:=false;
  408. iolabel:=nil;
  409. loada5:=true;
  410. no_virtual_call:=false;
  411. unusedregisters:=unused;
  412. if not assigned(p^.procdefinition) then
  413. exit;
  414. { only if no proc var }
  415. if not(assigned(p^.right)) then
  416. is_con_or_destructor:=(potype_constructor=p^.procdefinition^.proctypeoption)
  417. or (potype_destructor=p^.procdefinition^.proctypeoption);
  418. { proc variables destroy all registers }
  419. if (p^.right=nil) and
  420. { virtual methods too }
  421. (po_virtualmethod in p^.procdefinition^.procoptions) then
  422. begin
  423. if (po_iocheck in p^.procdefinition^.procoptions) and
  424. not(po_iocheck in aktprocsym^.definition^.procoptions) and
  425. (cs_check_io in aktlocalswitches) then
  426. begin
  427. getlabel(iolabel);
  428. emitl(A_LABEL,iolabel);
  429. end
  430. else iolabel:=nil;
  431. { save all used registers }
  432. pushusedregisters(pushed,pprocdef(p^.procdefinition)^.usedregisters);
  433. { give used registers through }
  434. usedinproc:=usedinproc or pprocdef(p^.procdefinition)^.usedregisters;
  435. end
  436. else
  437. begin
  438. pushusedregisters(pushed,$ffff);
  439. usedinproc:=$ffff;
  440. { no IO check for methods and procedure variables }
  441. iolabel:=nil;
  442. end;
  443. { generate the code for the parameter and push them }
  444. oldpushedparasize:=pushedparasize;
  445. pushedparasize:=0;
  446. if (p^.resulttype<>pdef(voiddef)) and
  447. ret_in_param(p^.resulttype) then
  448. begin
  449. funcretref.symbol:=nil;
  450. {$ifdef test_dest_loc}
  451. if dest_loc_known and (dest_loc_tree=p) and
  452. (dest_loc.loc in [LOC_REFERENCE,LOC_MEM]) then
  453. begin
  454. funcretref:=dest_loc.reference;
  455. if assigned(dest_loc.reference.symbol) then
  456. funcretref.symbol:=stringdup(dest_loc.reference.symbol^);
  457. in_dest_loc:=true;
  458. end
  459. else
  460. {$endif test_dest_loc}
  461. gettempofsizereference(p^.procdefinition^.retdef^.size,funcretref);
  462. end;
  463. if assigned(p^.left) then
  464. begin
  465. pushedparasize:=0;
  466. { be found elsewhere }
  467. if assigned(p^.right) then
  468. secondcallparan(p^.left,pprocvardef(p^.right^.resulttype)^.para1,
  469. (pocall_leftright in p^.procdefinition^.proccalloptions))
  470. else
  471. secondcallparan(p^.left,p^.procdefinition^.para1,
  472. (pocall_leftright in p^.procdefinition^.proccalloptions));
  473. end;
  474. params:=p^.left;
  475. p^.left:=nil;
  476. if ret_in_param(p^.resulttype) then
  477. begin
  478. emitpushreferenceaddr(exprasmlist,funcretref);
  479. inc(pushedparasize,4);
  480. end;
  481. { overloaded operator have no symtable }
  482. if (p^.right=nil) then
  483. begin
  484. { push self }
  485. if assigned(p^.symtable) and
  486. (p^.symtable^.symtabletype=withsymtable) then
  487. begin
  488. { dirty trick to avoid the secondcall below }
  489. p^.methodpointer:=genzeronode(callparan);
  490. p^.methodpointer^.location.loc:=LOC_REGISTER;
  491. p^.methodpointer^.location.register:=R_A5;
  492. { change dispose type !! }
  493. p^.disposetyp:=dt_mbleft_and_method;
  494. { make a reference }
  495. new(r);
  496. reset_reference(r^);
  497. r^.offset:=p^.symtable^.datasize;
  498. r^.base:=procinfo^.framepointer;
  499. exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOVE,S_L,r,R_A5)));
  500. end;
  501. { push self }
  502. if assigned(p^.symtable) and
  503. ((p^.symtable^.symtabletype=objectsymtable) or
  504. (p^.symtable^.symtabletype=withsymtable)) then
  505. begin
  506. if assigned(p^.methodpointer) then
  507. begin
  508. case p^.methodpointer^.treetype of
  509. typen :
  510. begin
  511. { direct call to inherited method }
  512. if po_abstractmethod in p^.procdefinition^.procoptions then
  513. begin
  514. CGMessage(cg_e_cant_call_abstract_method);
  515. goto dont_call;
  516. end;
  517. { generate no virtual call }
  518. no_virtual_call:=true;
  519. if (sp_static in p^.symtableprocentry^.symoptions) then
  520. begin
  521. { well lets put the VMT address directly into a5 }
  522. { it is kind of dirty but that is the simplest }
  523. { way to accept virtual static functions (PM) }
  524. loada5:=true;
  525. exprasmlist^.concat(new(paicpu,op_csymbol_reg(A_MOVE,S_L,
  526. newcsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,0),R_A5)));
  527. exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  528. end
  529. else
  530. { this is a member call, so A5 isn't modfied }
  531. loada5:=false;
  532. { a class destructor needs a flag }
  533. if pobjectdef(p^.methodpointer^.resulttype)^.is_class and
  534. assigned(aktprocsym) and
  535. (aktprocsym^.definition^.proctypeoption=potype_destructor) then
  536. begin
  537. push_int(0);
  538. exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  539. end;
  540. if not(is_con_or_destructor and
  541. pobjectdef(p^.methodpointer^.resulttype)^.is_class and
  542. assigned(aktprocsym) and
  543. (aktprocsym^.definition^.proctypeoption in [potype_constructor,potype_destructor])
  544. ) then
  545. exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  546. { if an inherited con- or destructor should be }
  547. { called in a con- or destructor then a warning }
  548. { will be made }
  549. { con- and destructors need a pointer to the vmt }
  550. if is_con_or_destructor and
  551. not(pobjectdef(p^.methodpointer^.resulttype)^.is_class) and
  552. assigned(aktprocsym) then
  553. begin
  554. if not(aktprocsym^.definition^.proctypeoption in
  555. [potype_constructor,potype_destructor]) then
  556. CGMessage(cg_w_member_cd_call_from_method);
  557. end;
  558. { class destructors get there flag below }
  559. if is_con_or_destructor and
  560. not(pobjectdef(p^.methodpointer^.resulttype)^.is_class and
  561. assigned(aktprocsym) and
  562. (aktprocsym^.definition^.proctypeoption=potype_destructor)) then
  563. push_int(0);
  564. end;
  565. hnewn : begin
  566. { extended syntax of new }
  567. { A5 must be zero }
  568. exprasmlist^.concat(new(paicpu,op_const_reg(A_MOVE,S_L,0,R_A5)));
  569. emit_reg_reg(A_MOVE,S_L,R_A5, R_SPPUSH);
  570. { insert the vmt }
  571. exprasmlist^.concat(new(paicpu,op_csymbol(A_PEA,S_L,
  572. newcsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname,0))));
  573. extended_new:=true;
  574. end;
  575. hdisposen : begin
  576. secondpass(p^.methodpointer);
  577. { destructor with extended syntax called from dispose }
  578. { hdisposen always deliver LOC_REFRENZ }
  579. exprasmlist^.concat(new(paicpu,op_ref_reg(A_LEA,S_L,
  580. newreference(p^.methodpointer^.location.reference),R_A5)));
  581. del_reference(p^.methodpointer^.location.reference);
  582. exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  583. exprasmlist^.concat(new(paicpu,op_csymbol(A_PEA,S_L,
  584. newcsymbol(pobjectdef
  585. (p^.methodpointer^.resulttype)^.vmt_mangledname,0))));
  586. end;
  587. else
  588. begin
  589. { call to a instance member }
  590. if (p^.symtable^.symtabletype<>withsymtable) then
  591. begin
  592. secondpass(p^.methodpointer);
  593. case p^.methodpointer^.location.loc of
  594. LOC_REGISTER :
  595. begin
  596. ungetregister32(p^.methodpointer^.location.register);
  597. emit_reg_reg(A_MOVE,S_L,p^.methodpointer^.location.register,R_A5);
  598. end;
  599. else
  600. begin
  601. if (p^.methodpointer^.resulttype^.deftype=objectdef) and
  602. pobjectdef(p^.methodpointer^.resulttype)^.is_class then
  603. exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOVE,S_L,
  604. newreference(p^.methodpointer^.location.reference),R_A5)))
  605. else
  606. Begin
  607. exprasmlist^.concat(new(paicpu,op_ref_reg(A_LEA,S_L,
  608. newreference(p^.methodpointer^.location.reference),R_A5)));
  609. end;
  610. del_reference(p^.methodpointer^.location.reference);
  611. end;
  612. end;
  613. end;
  614. { when calling a class method, we have to load ESI with the VMT !
  615. But, not for a class method via self }
  616. if not(po_containsself in p^.procdefinition^.procoptions) then
  617. begin
  618. if (po_classmethod in p^.procdefinition^.procoptions) and
  619. not(p^.methodpointer^.resulttype^.deftype=classrefdef) then
  620. begin
  621. { class method needs current VMT }
  622. new(r);
  623. reset_reference(r^);
  624. r^.base:=R_A5;
  625. r^.offset:= pprocdef(p^.procdefinition)^._class^.vmt_offset;
  626. exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOVE,S_L,r,R_A5)));
  627. end;
  628. { direct call to destructor: don't remove data! }
  629. if (p^.procdefinition^.proctypeoption=potype_destructor) and
  630. (p^.methodpointer^.resulttype^.deftype=objectdef) and
  631. (pobjectdef(p^.methodpointer^.resulttype)^.is_class) then
  632. push_int(1);
  633. { direct call to class constructor, don't allocate memory }
  634. if (p^.procdefinition^.proctypeoption=potype_constructor) and
  635. (p^.methodpointer^.resulttype^.deftype=objectdef) and
  636. (pobjectdef(p^.methodpointer^.resulttype)^.is_class) then
  637. push_int(0)
  638. else
  639. exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  640. if is_con_or_destructor then
  641. begin
  642. { classes don't get a VMT pointer pushed }
  643. if (p^.methodpointer^.resulttype^.deftype=objectdef) and
  644. not(pobjectdef(p^.methodpointer^.resulttype)^.is_class) then
  645. begin
  646. if (p^.procdefinition^.proctypeoption=potype_constructor) then
  647. begin
  648. { it's no bad idea, to insert the VMT }
  649. exprasmlist^.concat(new(paicpu,op_csymbol(A_PEA,S_L,
  650. newcsymbol(pobjectdef(
  651. p^.methodpointer^.resulttype)^.vmt_mangledname,0))));
  652. end
  653. { destructors haven't to dispose the instance, if this is }
  654. { a direct call }
  655. else
  656. push_int(0);
  657. end;
  658. end;
  659. end;
  660. end;
  661. end;
  662. end
  663. else
  664. begin
  665. if (po_classmethod in p^.procdefinition^.procoptions) and
  666. not(
  667. assigned(aktprocsym) and
  668. (po_classmethod in aktprocsym^.definition^.procoptions)
  669. ) then
  670. begin
  671. { class method needs current VMT }
  672. new(r);
  673. reset_reference(r^);
  674. r^.base:=R_A5;
  675. r^.offset:= pprocdef(p^.procdefinition)^._class^.vmt_offset;
  676. exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOVE,S_L,r,R_A5)));
  677. end
  678. else
  679. begin
  680. { member call, A5 isn't modified }
  681. loada5:=false;
  682. end;
  683. exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVE,S_L,R_A5,R_SPPUSH)));
  684. { but a con- or destructor here would probably almost }
  685. { always be placed wrong }
  686. if is_con_or_destructor then
  687. begin
  688. CGMessage(cg_w_member_cd_call_from_method);
  689. { not insert VMT pointer } { VMT-Zeiger nicht eintragen }
  690. push_int(0);
  691. end;
  692. end;
  693. end;
  694. { push base pointer ?}
  695. if (lexlevel>=normal_function_level) and assigned(pprocdef(p^.procdefinition)^.parast) and
  696. ((pprocdef(p^.procdefinition)^.parast^.symtablelevel)>normal_function_level) then
  697. begin
  698. { if we call a nested function in a method, we must }
  699. { push also SELF! }
  700. { THAT'S NOT TRUE, we have to load ESI via frame pointer }
  701. { access }
  702. {
  703. begin
  704. loadesi:=false;
  705. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_ESI)));
  706. end;
  707. }
  708. if lexlevel=(pprocdef(p^.procdefinition)^.parast^.symtablelevel) then
  709. begin
  710. new(r);
  711. reset_reference(r^);
  712. r^.offset:=procinfo^.framepointer_offset;
  713. r^.base:=procinfo^.framepointer;
  714. exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOVE,S_L,r,R_SPPUSH)))
  715. end
  716. { this is only true if the difference is one !!
  717. but it cannot be more !! }
  718. else if lexlevel=(pprocdef(p^.procdefinition)^.parast^.symtablelevel)-1 then
  719. begin
  720. exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVE,S_L,procinfo^.framepointer,R_SPPUSH)))
  721. end
  722. else if lexlevel>(pprocdef(p^.procdefinition)^.parast^.symtablelevel) then
  723. begin
  724. hregister:=getaddressreg;
  725. new(r);
  726. reset_reference(r^);
  727. r^.offset:=procinfo^.framepointer_offset;
  728. r^.base:=procinfo^.framepointer;
  729. exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOVE,S_L,r,hregister)));
  730. for i:=(pprocdef(p^.procdefinition)^.parast^.symtablelevel) to lexlevel-1 do
  731. begin
  732. new(r);
  733. reset_reference(r^);
  734. {we should get the correct frame_pointer_offset at each level
  735. how can we do this !!! }
  736. r^.offset:=procinfo^.framepointer_offset;
  737. r^.base:=hregister;
  738. exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOVE,S_L,r,hregister)));
  739. end;
  740. exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVE,S_L,hregister,R_SPPUSH)));
  741. ungetregister32(hregister);
  742. end
  743. else
  744. internalerror(25000);
  745. end;
  746. if (po_virtualmethod in p^.procdefinition^.procoptions) and
  747. not(no_virtual_call) then
  748. begin
  749. { static functions contain the vmt_address in ESI }
  750. { also class methods }
  751. if assigned(aktprocsym) then
  752. begin
  753. if (((sp_static in aktprocsym^.symoptions) or
  754. (po_classmethod in aktprocsym^.definition^.procoptions)) and
  755. ((p^.methodpointer=nil) or (p^.methodpointer^.treetype=typen)))
  756. or
  757. (po_staticmethod in p^.procdefinition^.procoptions) or
  758. (p^.procdefinition^.proctypeoption=potype_constructor) or
  759. { A5 is loaded earlier }
  760. (po_classmethod in p^.procdefinition^.procoptions) then
  761. begin
  762. new(r);
  763. reset_reference(r^);
  764. r^.base:=R_a5;
  765. end
  766. else
  767. begin
  768. new(r);
  769. reset_reference(r^);
  770. r^.base:=R_a5;
  771. r^.offset:= pprocdef(p^.procdefinition)^._class^.vmt_offset;
  772. exprasmlist^.concat(new(paicpu,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. end
  778. else
  779. begin
  780. new(r);
  781. reset_reference(r^);
  782. r^.base:=R_a5;
  783. exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOVE,S_L,r,R_a0)));
  784. new(r);
  785. reset_reference(r^);
  786. r^.base:=R_a0;
  787. end;
  788. if pprocdef(p^.procdefinition)^.extnumber=-1 then
  789. internalerror(1609991);
  790. r^.offset:=pprocdef(p^.procdefinition)^.extnumber*4+12;
  791. if (cs_check_range in aktlocalswitches) then
  792. begin
  793. { If the base is already A0, the no instruction will }
  794. { be emitted! }
  795. emit_reg_reg(A_MOVE,S_L,r^.base,R_A0);
  796. emitcall('FPC_CHECK_OBJECT',true);
  797. end;
  798. { This was wrong we must then load the address into the }
  799. { register a0 and/or a5 }
  800. { Because doing an indirect call with offset is NOT }
  801. { allowed on the m68k! }
  802. exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOVE,S_L,newreference(r^),R_A0)));
  803. { clear the reference }
  804. reset_reference(r^);
  805. r^.base := R_A0;
  806. exprasmlist^.concat(new(paicpu,op_ref(A_JSR,S_NO,r)));
  807. end
  808. else if pocall_palmossyscall in p^.procdefinition^.proccalloptions then
  809. begin
  810. exprasmlist^.concat(new(paicpu,op_const(A_TRAP,S_NO,15)));
  811. exprasmlist^.concat(new(pai_const,init_16bit(pprocdef(p^.procdefinition)^.extnumber)));
  812. end
  813. else
  814. emitcall(pprocdef(p^.procdefinition)^.mangledname,
  815. (p^.symtableproc^.symtabletype=unitsymtable) or
  816. ((p^.symtableproc^.symtabletype=objectsymtable) and
  817. (pobjectdef(p^.symtableproc^.defowner)^.owner^.symtabletype=unitsymtable))or
  818. ((p^.symtableproc^.symtabletype=withsymtable) and
  819. (pobjectdef(p^.symtableproc^.defowner)^.owner^.symtabletype=unitsymtable)));
  820. if (pocall_clearstack in p^.procdefinition^.proccalloptions) then
  821. begin
  822. if (pushedparasize > 0) and (pushedparasize < 9) then
  823. { restore the stack, to its initial value }
  824. exprasmlist^.concat(new(paicpu,op_const_reg(A_ADDQ,S_L,pushedparasize,R_SP)))
  825. else
  826. { restore the stack, to its initial value }
  827. exprasmlist^.concat(new(paicpu,op_const_reg(A_ADDA,S_L,pushedparasize,R_SP)));
  828. end;
  829. end
  830. else
  831. begin
  832. secondpass(p^.right);
  833. case p^.right^.location.loc of
  834. LOC_REGISTER,
  835. LOC_CREGISTER : begin
  836. if p^.right^.location.register in [R_D0..R_D7] then
  837. begin
  838. reg := getaddressreg;
  839. emit_reg_reg(A_MOVE,S_L,p^.right^.location.register,reg);
  840. new(ref);
  841. reset_reference(ref^);
  842. ref^.base := reg;
  843. exprasmlist^.concat(new(paicpu,op_ref(A_JSR,S_NO,ref)));
  844. ungetregister(reg);
  845. end
  846. else
  847. begin
  848. new(ref);
  849. reset_reference(ref^);
  850. ref^.base := p^.right^.location.register;
  851. exprasmlist^.concat(new(paicpu,op_ref(A_JSR,S_NO,ref)));
  852. end;
  853. ungetregister32(p^.right^.location.register);
  854. end
  855. else
  856. begin
  857. if assigned(p^.right^.location.reference.symbol) then
  858. { Here we have a symbolic name to the routine, so solve }
  859. { problem by loading the address first, and then emitting }
  860. { the call. }
  861. begin
  862. exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOVE,S_L,
  863. newreference(p^.right^.location.reference),R_A1)));
  864. new(ref);
  865. reset_reference(ref^);
  866. ref^.base := R_A1;
  867. exprasmlist^.concat(new(paicpu,op_ref(A_JSR,S_NO,ref)));
  868. end
  869. else
  870. begin
  871. exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOVE,S_L,
  872. newreference(p^.right^.location.reference),R_A1)));
  873. new(ref);
  874. reset_reference(ref^);
  875. ref^.base := R_A1;
  876. exprasmlist^.concat(new(paicpu,op_ref(A_JSR,S_NO,ref)));
  877. end;
  878. del_reference(p^.right^.location.reference);
  879. end;
  880. end;
  881. end;
  882. dont_call:
  883. pushedparasize:=oldpushedparasize;
  884. unused:=unusedregisters;
  885. { handle function results }
  886. if p^.resulttype<>pdef(voiddef) then
  887. begin
  888. { a contructor could be a function with boolean result }
  889. if (p^.right=nil) and
  890. (p^.procdefinition^.proctypeoption=potype_constructor) and
  891. { quick'n'dirty check if it is a class or an object }
  892. (p^.resulttype^.deftype=orddef) then
  893. begin
  894. p^.location.loc:=LOC_FLAGS;
  895. p^.location.resflags:=F_NE;
  896. if extended_new then
  897. begin
  898. {$ifdef test_dest_loc}
  899. if dest_loc_known and (dest_loc_tree=p) then
  900. mov_reg_to_dest(p,S_L,R_EAX)
  901. else
  902. {$endif test_dest_loc}
  903. hregister:=getregister32;
  904. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  905. p^.location.register:=hregister;
  906. end;
  907. end
  908. { structed results are easy to handle.... }
  909. else if ret_in_param(p^.resulttype) then
  910. begin
  911. p^.location.loc:=LOC_MEM;
  912. stringdispose(p^.location.reference.symbol);
  913. p^.location.reference:=funcretref;
  914. end
  915. else
  916. begin
  917. if (p^.resulttype^.deftype in [orddef,enumdef]) then
  918. begin
  919. p^.location.loc:=LOC_REGISTER;
  920. case p^.resulttype^.size of
  921. 4 :
  922. begin
  923. hregister:=getregister32;
  924. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  925. p^.location.register:=hregister;
  926. end;
  927. 1 :
  928. begin
  929. hregister:=getregister32;
  930. emit_reg_reg(A_MOVE,S_B,R_D0,hregister);
  931. p^.location.register:=hregister;
  932. end;
  933. 2:
  934. begin
  935. hregister:=getregister32;
  936. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  937. p^.location.register:=hregister;
  938. end;
  939. else internalerror(7);
  940. end
  941. end
  942. else if (p^.resulttype^.deftype=floatdef) then
  943. case pfloatdef(p^.resulttype)^.typ of
  944. f32bit :
  945. begin
  946. p^.location.loc:=LOC_REGISTER;
  947. hregister:=getregister32;
  948. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  949. p^.location.register:=hregister;
  950. end;
  951. s32real : Begin
  952. p^.location.loc:=LOC_FPU;
  953. hregister:=getregister32;
  954. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  955. p^.location.fpureg:=hregister;
  956. end;
  957. s64comp,s64real,s80real: begin
  958. if cs_fp_emulation in aktmoduleswitches then
  959. begin
  960. p^.location.loc:=LOC_FPU;
  961. hregister:=getregister32;
  962. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  963. p^.location.fpureg:=hregister;
  964. end
  965. else
  966. begin
  967. { TRUE FPU mode }
  968. p^.location.loc:=LOC_FPU;
  969. { on exit of function result in R_FP0 }
  970. p^.location.fpureg:=R_FP0;
  971. end;
  972. end;
  973. else
  974. begin
  975. p^.location.loc:=LOC_FPU;
  976. p^.location.fpureg:=R_FP0;
  977. end;
  978. end {end case }
  979. else
  980. begin
  981. p^.location.loc:=LOC_REGISTER;
  982. hregister:=getregister32;
  983. emit_reg_reg(A_MOVE,S_L,R_D0,hregister);
  984. p^.location.register:=hregister;
  985. end;
  986. end;
  987. end;
  988. { perhaps i/o check ? }
  989. if iolabel<>nil then
  990. begin
  991. exprasmlist^.concat(new(paicpu,op_csymbol(A_PEA,S_L,newcsymbol(iolabel^.name,0))));
  992. emitcall('FPC_IOCHECK',true);
  993. end;
  994. { restore registers }
  995. popusedregisters(pushed);
  996. { at last, restore instance pointer (SELF) }
  997. if loada5 then
  998. maybe_loada5;
  999. pp:=params;
  1000. while assigned(pp) do
  1001. begin
  1002. if assigned(pp^.left) then
  1003. if (pp^.left^.location.loc=LOC_REFERENCE) or
  1004. (pp^.left^.location.loc=LOC_MEM) then
  1005. ungetiftemp(pp^.left^.location.reference);
  1006. pp:=pp^.right;
  1007. end;
  1008. disposetree(params);
  1009. end;
  1010. {*****************************************************************************
  1011. SecondProcInlineN
  1012. *****************************************************************************}
  1013. procedure secondprocinline(var p : ptree);
  1014. begin
  1015. InternalError(132421);
  1016. end;
  1017. end.
  1018. {
  1019. $Log$
  1020. Revision 1.23 2000-01-07 01:14:21 peter
  1021. * updated copyright to 2000
  1022. Revision 1.22 1999/12/22 01:01:47 peter
  1023. - removed freelabel()
  1024. * added undefined label detection in internal assembler, this prevents
  1025. a lot of ld crashes and wrong .o files
  1026. * .o files aren't written anymore if errors have occured
  1027. * inlining of assembler labels is now correct
  1028. Revision 1.21 1999/11/06 14:34:18 peter
  1029. * truncated log to 20 revs
  1030. Revision 1.20 1999/09/27 23:44:48 peter
  1031. * procinfo is now a pointer
  1032. * support for result setting in sub procedure
  1033. Revision 1.19 1999/09/16 23:05:51 florian
  1034. * m68k compiler is again compilable (only gas writer, no assembler reader)
  1035. Revision 1.18 1999/09/16 11:34:52 pierre
  1036. * typo correction
  1037. Revision 1.17 1998/12/11 00:02:58 peter
  1038. + globtype,tokens,version unit splitted from globals
  1039. Revision 1.16 1998/11/13 15:40:15 pierre
  1040. + added -Se in Makefile cvstest target
  1041. + lexlevel cleanup
  1042. normal_function_level main_program_level and unit_init_level defined
  1043. * tins_cache grown to A_EMMS (gave range check error in asm readers)
  1044. (test added in code !)
  1045. * -Un option was wrong
  1046. * _FAIL and _SELF only keyword inside
  1047. constructors and methods respectively
  1048. Revision 1.15 1998/11/12 11:19:41 pierre
  1049. * fix for first line of function break
  1050. Revision 1.14 1998/10/21 15:12:51 pierre
  1051. * bug fix for IOCHECK inside a procedure with iocheck modifier
  1052. * removed the GPF for unexistant overloading
  1053. (firstcall was called with procedinition=nil !)
  1054. * changed typen to what Florian proposed
  1055. gentypenode(p : pdef) sets the typenodetype field
  1056. and resulttype is only set if inside bt_type block !
  1057. Revision 1.13 1998/10/20 08:06:45 pierre
  1058. * several memory corruptions due to double freemem solved
  1059. => never use p^.loc.location:=p^.left^.loc.location;
  1060. + finally I added now by default
  1061. that ra386dir translates global and unit symbols
  1062. + added a first field in tsymtable and
  1063. a nextsym field in tsym
  1064. (this allows to obtain ordered type info for
  1065. records and objects in gdb !)
  1066. Revision 1.12 1998/10/19 08:54:53 pierre
  1067. * wrong stabs info corrected once again !!
  1068. + variable vmt offset with vmt field only if required
  1069. implemented now !!!
  1070. Revision 1.11 1998/10/16 13:12:46 pierre
  1071. * added vmt_offsets in destructors code also !!!
  1072. * vmt_offset code for m68k
  1073. Revision 1.10 1998/10/15 12:41:16 pierre
  1074. * last memory leaks found when compiler
  1075. a native atari compiler fixed
  1076. Revision 1.9 1998/10/14 11:28:16 florian
  1077. * emitpushreferenceaddress gets now the asmlist as parameter
  1078. * m68k version compiles with -duseansistrings
  1079. Revision 1.8 1998/10/13 16:50:04 pierre
  1080. * undid some changes of Peter that made the compiler wrong
  1081. for m68k (I had to reinsert some ifdefs)
  1082. * removed several memory leaks under m68k
  1083. * removed the meory leaks for assembler readers
  1084. * cross compiling shoud work again better
  1085. ( crosscompiling sysamiga works
  1086. but as68k still complain about some code !)
  1087. Revision 1.7 1998/10/13 08:19:27 pierre
  1088. + source_os is now set correctly for cross-processor compilers
  1089. (tos contains all target_infos and
  1090. we use CPU86 and CPU68 conditionals to
  1091. get the source operating system
  1092. this only works if you do not undefine
  1093. the source target !!)
  1094. * several cg68k memory leaks fixed
  1095. + started to change the code so that it should be possible to have
  1096. a complete compiler (both for m68k and i386 !!)
  1097. Revision 1.6 1998/09/20 12:26:38 peter
  1098. * merged fixes
  1099. Revision 1.5 1998/09/17 09:42:22 peter
  1100. + pass_2 for cg386
  1101. * Message() -> CGMessage() for pass_1/pass_2
  1102. Revision 1.4 1998/09/14 10:43:55 peter
  1103. * all internal RTL functions start with FPC_
  1104. Revision 1.3.2.1 1998/09/20 12:20:09 peter
  1105. * Fixed stack not on 4 byte boundary when doing a call
  1106. Revision 1.3 1998/09/04 08:41:43 peter
  1107. * updated some error CGMessages
  1108. Revision 1.2 1998/09/01 12:47:59 peter
  1109. * use pdef^.size instead of orddef^.typ
  1110. }