cgobj.pas 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. This unit implements the basic code generator object
  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 cgobj;
  19. interface
  20. uses
  21. cobjects,aasm,symtable
  22. {$I cpuunit.inc}
  23. ;
  24. type
  25. qword = comp;
  26. pcg = ^tcg;
  27. tcg = object
  28. constructor init;
  29. destructor done;virtual;
  30. procedure a_call_name_ext(list : paasmoutput;const s : string;
  31. offset : longint);
  32. {************************************************}
  33. { code generation for subroutine entry/exit code }
  34. { helper routines }
  35. procedure g_initialize_data(p : psym);
  36. procedure g_incr_data(p : psym);
  37. procedure g_finalize_data(p : pnamedindexobject);
  38. {$ifndef VALUEPARA}
  39. procedure g_copyopenarrays(p : pnamedindexobject);
  40. {$else}
  41. procedure g_copyvalueparas(p : pnamedindexobject);
  42. {$endif}
  43. procedure g_entrycode(list : paasmoutput;
  44. const proc_names : tstringcontainer;make_global : boolean;
  45. stackframe : longint;var parasize : longint;
  46. var nostackframe : boolean;inlined : boolean);
  47. procedure g_exitcode(list : paasmoutput;parasize : longint;
  48. nostackframe,inlined : boolean);
  49. { string helper routines }
  50. procedure g_decransiref(const ref : treference);
  51. procedure g_removetemps(list : paasmoutput;p : plinkedlist);
  52. {**********************************}
  53. { these methods must be overriden: }
  54. procedure a_push_reg(list : paasmoutput;r : tregister);virtual;
  55. procedure a_call_name(list : paasmoutput;const s : string;
  56. offset : longint);virtual;
  57. procedure a_load_const8_ref(list : paasmoutput;b : byte;const ref : treference);virtual;
  58. procedure a_load_const16_ref(list : paasmoutput;w : word;const ref : treference);virtual;
  59. procedure a_load_const32_ref(list : paasmoutput;l : longint;const ref : treference);virtual;
  60. procedure a_load_const64_ref(list : paasmoutput;q : qword;const ref : treference);virtual;
  61. procedure g_stackframe_entry(list : paasmoutput;localsize : longint);virtual;
  62. procedure g_maybe_loadself(list : paasmoutput);virtual;
  63. {********************************************************}
  64. { these methods can be overriden for extra functionality }
  65. { the following methods do nothing: }
  66. procedure g_interrupt_stackframe_entry(list : paasmoutput);virtual;
  67. procedure g_interrupt_stackframe_exit(list : paasmoutput);virtual;
  68. procedure g_profilecode(list : paasmoutput);virtual;
  69. procedure g_stackcheck(list : paasmoutput;stackframesize : longint);virtual;
  70. { passing parameters, per default the parameter is pushed }
  71. { nr gives the number of the parameter (enumerated from }
  72. { left to right), this allows to move the parameter to }
  73. { register, if the cpu supports register calling }
  74. { conventions }
  75. procedure a_param_reg(list : paasmoutput;r : tregister;nr : longint);virtual;
  76. procedure a_param_const8(list : paasmoutput;b : byte;nr : longint);virtual;
  77. procedure a_param_const16(list : paasmoutput;w : word;nr : longint);virtual;
  78. procedure a_param_const32(list : paasmoutput;l : longint;nr : longint);virtual;
  79. procedure a_param_const64(list : paasmoutput;q : qword;nr : longint);virtual;
  80. end;
  81. var
  82. cg : pcg; { this is the main code generator class }
  83. implementation
  84. uses
  85. globals,globtype,options,files,gdb,systems,
  86. ppu,cgbase,verbose,types,tgobj,tgcpu
  87. ;
  88. constructor tcg.init;
  89. begin
  90. end;
  91. destructor tcg.done;
  92. begin
  93. end;
  94. {*****************************************************************************
  95. per default, this methods nothing, can overriden
  96. *****************************************************************************}
  97. procedure tcg.g_interrupt_stackframe_entry(list : paasmoutput);
  98. begin
  99. end;
  100. procedure tcg.g_interrupt_stackframe_exit(list : paasmoutput);
  101. begin
  102. end;
  103. procedure tcg.g_profilecode(list : paasmoutput);
  104. begin
  105. end;
  106. procedure tcg.a_param_reg(list : paasmoutput;r : tregister;nr : longint);
  107. begin
  108. a_push_reg(list,r);
  109. end;
  110. procedure tcg.a_param_const8(list : paasmoutput;b : byte;nr : longint);
  111. begin
  112. {!!!!!!!! a_push_const8(list,b); }
  113. end;
  114. procedure tcg.a_param_const16(list : paasmoutput;w : word;nr : longint);
  115. begin
  116. {!!!!!!!! a_push_const16(list,w); }
  117. end;
  118. procedure tcg.a_param_const32(list : paasmoutput;l : longint;nr : longint);
  119. begin
  120. {!!!!!!!! a_push_const32(list,l); }
  121. end;
  122. procedure tcg.a_param_const64(list : paasmoutput;q : qword;nr : longint);
  123. begin
  124. {!!!!!!!! a_push_const64(list,q); }
  125. end;
  126. procedure tcg.g_stackcheck(list : paasmoutput;stackframesize : longint);
  127. begin
  128. a_param_const32(list,stackframesize,1);
  129. a_call_name_ext(list,'FPC_STACKCHECK',0);
  130. end;
  131. procedure tcg.a_call_name_ext(list : paasmoutput;const s : string;
  132. offset : longint);
  133. begin
  134. a_call_name(list,s,offset);
  135. { concat_external(s,m); }
  136. end;
  137. {*****************************************************************************
  138. String helper routines
  139. *****************************************************************************}
  140. procedure tcg.g_removetemps(list : paasmoutput;p : plinkedlist);
  141. var
  142. hp : ptemptodestroy;
  143. pushedregs : tpushed;
  144. begin
  145. hp:=ptemptodestroy(p^.first);
  146. if not(assigned(hp)) then
  147. exit;
  148. tg.pushusedregisters(pushedregs,$ff);
  149. while assigned(hp) do
  150. begin
  151. if is_ansistring(hp^.typ) then
  152. begin
  153. g_decransiref(hp^.address);
  154. tg.ungetiftemp(hp^.address);
  155. end;
  156. hp:=ptemptodestroy(hp^.next);
  157. end;
  158. tg.popusedregisters(pushedregs);
  159. end;
  160. procedure tcg.g_decransiref(const ref : treference);
  161. begin
  162. {!!!!!!!!!}
  163. { emitpushreferenceaddr(exprasmlist,ref);
  164. emitcall('FPC_ANSISTR_DECR_REF',true); }
  165. end;
  166. {*****************************************************************************
  167. Code generation for subroutine entry- and exit code
  168. *****************************************************************************}
  169. { generates the code for initialisation of local data }
  170. procedure tcg.g_initialize_data(p : psym);
  171. var
  172. r : preference;
  173. hr : treference;
  174. begin
  175. {$ifdef dummy}
  176. if (p^.typ=varsym) and
  177. assigned(pvarsym(p)^.definition) and
  178. pvarsym(p)^.definition^.needs_inittable and
  179. not((pvarsym(p)^.definition^.deftype=objectdef) and
  180. pobjectdef(pvarsym(p)^.definition)^.isclass) then
  181. begin
  182. if is_ansistring(pvarsym(p)^.definition) or
  183. is_widestring(pvarsym(p)^.definition) then
  184. begin
  185. new(r);
  186. reset_reference(r^);
  187. if p^.owner^.symtabletype=localsymtable then
  188. begin
  189. r^.base:=procinfo.framepointer;
  190. r^.offset:=-pvarsym(p)^.address;
  191. end
  192. else
  193. r^.symbol:=stringdup(pvarsym(p)^.mangledname);
  194. curlist^.concat(new(pai386,op_const_ref(A_MOV,S_L,0,r)));
  195. end
  196. else
  197. begin
  198. reset_reference(hr);
  199. hr.symbol:=stringdup(lab2str(pvarsym(p)^.definition^.get_inittable_label));
  200. emitpushreferenceaddr(curlist,hr);
  201. clear_reference(hr);
  202. if p^.owner^.symtabletype=localsymtable then
  203. begin
  204. hr.base:=procinfo.framepointer;
  205. hr.offset:=-pvarsym(p)^.address;
  206. end
  207. else
  208. begin
  209. hr.symbol:=stringdup(pvarsym(p)^.mangledname);
  210. end;
  211. emitpushreferenceaddr(curlist,hr);
  212. clear_reference(hr);
  213. curlist^.concat(new(pai386,
  214. op_csymbol(A_CALL,S_NO,newcsymbol('FPC_INITIALIZE',0))));
  215. if not(cs_compilesystem in aktmoduleswitches) then
  216. concat_external('FPC_INITIALIZE',EXT_NEAR);
  217. end;
  218. end;
  219. {$endif dummy}
  220. end;
  221. { generates the code for incrementing the reference count of parameters }
  222. procedure tcg.g_incr_data(p : psym);
  223. var
  224. hr : treference;
  225. begin
  226. {$ifdef dummy}
  227. if (p^.typ=varsym) and
  228. pvarsym(p)^.definition^.needs_inittable and
  229. ((pvarsym(p)^.varspez=vs_value) {or
  230. (pvarsym(p)^.varspez=vs_const) and
  231. not(dont_copy_const_param(pvarsym(p)^.definition))}) and
  232. not((pvarsym(p)^.definition^.deftype=objectdef) and
  233. pobjectdef(pvarsym(p)^.definition)^.isclass) then
  234. begin
  235. reset_reference(hr);
  236. hr.symbol:=stringdup(lab2str(pvarsym(p)^.definition^.get_inittable_label));
  237. emitpushreferenceaddr(curlist,hr);
  238. clear_reference(hr);
  239. hr.base:=procinfo.framepointer;
  240. hr.offset:=pvarsym(p)^.address+procinfo.call_offset;
  241. emitpushreferenceaddr(curlist,hr);
  242. clear_reference(hr);
  243. curlist^.concat(new(pai386,
  244. op_csymbol(A_CALL,S_NO,newcsymbol('FPC_ADDREF',0))));
  245. if not (cs_compilesystem in aktmoduleswitches) then
  246. concat_external('FPC_ADDREF',EXT_NEAR);
  247. end;
  248. {$endif}
  249. end;
  250. { generates the code for finalisation of local data }
  251. procedure tcg.g_finalize_data(p : pnamedindexobject);
  252. var
  253. hr : treference;
  254. begin
  255. {$ifdef dummy}
  256. if (p^.typ=varsym) and
  257. assigned(pvarsym(p)^.definition) and
  258. pvarsym(p)^.definition^.needs_inittable and
  259. not((pvarsym(p)^.definition^.deftype=objectdef) and
  260. pobjectdef(pvarsym(p)^.definition)^.isclass) then
  261. begin
  262. { not all kind of parameters need to be finalized }
  263. if (p^.owner^.symtabletype=parasymtable) and
  264. ((pvarsym(p)^.varspez=vs_var) or
  265. (pvarsym(p)^.varspez=vs_const) { and
  266. (dont_copy_const_param(pvarsym(p)^.definition)) } ) then
  267. exit;
  268. reset_reference(hr);
  269. hr.symbol:=stringdup(lab2str(pvarsym(p)^.definition^.get_inittable_label));
  270. emitpushreferenceaddr(curlist,hr);
  271. clear_reference(hr);
  272. case p^.owner^.symtabletype of
  273. localsymtable:
  274. begin
  275. hr.base:=procinfo.framepointer;
  276. hr.offset:=-pvarsym(p)^.address;
  277. end;
  278. parasymtable:
  279. begin
  280. hr.base:=procinfo.framepointer;
  281. hr.offset:=pvarsym(p)^.address+procinfo.call_offset;
  282. end;
  283. else
  284. hr.symbol:=stringdup(pvarsym(p)^.mangledname);
  285. end;
  286. emitpushreferenceaddr(curlist,hr);
  287. clear_reference(hr);
  288. curlist^.concat(new(pai386,
  289. op_csymbol(A_CALL,S_NO,newcsymbol('FPC_FINALIZE',0))));
  290. if not (cs_compilesystem in aktmoduleswitches) then
  291. concat_external('FPC_FINALIZE',EXT_NEAR);
  292. end;
  293. {$endif dummy}
  294. end;
  295. { generates the code to make local copies of the value parameters }
  296. {$ifndef VALUEPARA}
  297. procedure tcg.g_copyopenarrays(p : pnamedindexobject);
  298. {$else}
  299. procedure tcg.g_copyvalueparas(p : pnamedindexobject);
  300. {$endif}
  301. var
  302. {$ifdef VALUEPARA}
  303. href1,href2 : treference;
  304. {$endif}
  305. r : preference;
  306. len : longint;
  307. opsize : topsize;
  308. oldexprasmlist : paasmoutput;
  309. begin
  310. {$ifdef dummy}
  311. if (p^.typ=varsym) and
  312. {$ifdef VALUEPARA}
  313. (pvarsym(p)^.varspez=vs_value) and
  314. (push_addr_param(pvarsym(p)^.definition)) then
  315. {$else}
  316. (pvarsym(p)^.varspez=vs_value) then
  317. {$endif}
  318. begin
  319. oldexprasmlist:=exprasmlist;
  320. exprasmlist:=curlist;
  321. {$ifdef VALUEPARA}
  322. {$ifdef GDB}
  323. if (cs_debuginfo in aktmoduleswitches) and
  324. (exprasmlist^.first=exprasmlist^.last) then
  325. exprasmlist^.concat(new(pai_force_line,init));
  326. {$endif GDB}
  327. {$endif}
  328. if is_open_array(pvarsym(p)^.definition) then
  329. begin
  330. { get stack space }
  331. new(r);
  332. reset_reference(r^);
  333. r^.base:=procinfo.framepointer;
  334. r^.offset:=pvarsym(p)^.address+4+procinfo.call_offset;
  335. curlist^.concat(new(pai386,
  336. op_ref_reg(A_MOV,S_L,r,R_EDI)));
  337. curlist^.concat(new(pai386,
  338. op_reg(A_INC,S_L,R_EDI)));
  339. curlist^.concat(new(pai386,
  340. op_const_reg(A_IMUL,S_L,
  341. parraydef(pvarsym(p)^.definition)^.definition^.size,R_EDI)));
  342. curlist^.concat(new(pai386,
  343. op_reg_reg(A_SUB,S_L,R_EDI,R_ESP)));
  344. { load destination }
  345. curlist^.concat(new(pai386,
  346. op_reg_reg(A_MOV,S_L,R_ESP,R_EDI)));
  347. { don't destroy the registers! }
  348. curlist^.concat(new(pai386,
  349. op_reg(A_PUSH,S_L,R_ECX)));
  350. curlist^.concat(new(pai386,
  351. op_reg(A_PUSH,S_L,R_ESI)));
  352. { load count }
  353. new(r);
  354. reset_reference(r^);
  355. r^.base:=procinfo.framepointer;
  356. r^.offset:=pvarsym(p)^.address+4+procinfo.call_offset;
  357. curlist^.concat(new(pai386,
  358. op_ref_reg(A_MOV,S_L,r,R_ECX)));
  359. { load source }
  360. new(r);
  361. reset_reference(r^);
  362. r^.base:=procinfo.framepointer;
  363. r^.offset:=pvarsym(p)^.address+procinfo.call_offset;
  364. curlist^.concat(new(pai386,
  365. op_ref_reg(A_MOV,S_L,r,R_ESI)));
  366. { scheduled .... }
  367. curlist^.concat(new(pai386,
  368. op_reg(A_INC,S_L,R_ECX)));
  369. { calculate size }
  370. len:=parraydef(pvarsym(p)^.definition)^.definition^.size;
  371. if (len and 3)=0 then
  372. begin
  373. opsize:=S_L;
  374. len:=len shr 2;
  375. end
  376. else
  377. if (len and 1)=0 then
  378. begin
  379. opsize:=S_W;
  380. len:=len shr 1;
  381. end;
  382. curlist^.concat(new(pai386,
  383. op_const_reg(A_IMUL,S_L,len,R_ECX)));
  384. curlist^.concat(new(pai386,
  385. op_none(A_REP,S_NO)));
  386. curlist^.concat(new(pai386,
  387. op_none(A_MOVS,opsize)));
  388. curlist^.concat(new(pai386,
  389. op_reg(A_POP,S_L,R_ESI)));
  390. curlist^.concat(new(pai386,
  391. op_reg(A_POP,S_L,R_ECX)));
  392. { patch the new address }
  393. new(r);
  394. reset_reference(r^);
  395. r^.base:=procinfo.framepointer;
  396. r^.offset:=pvarsym(p)^.address+procinfo.call_offset;
  397. curlist^.concat(new(pai386,
  398. op_reg_ref(A_MOV,S_L,R_ESP,r)));
  399. end
  400. {$ifdef VALUEPARA}
  401. else
  402. if is_shortstring(pvarsym(p)^.definition) then
  403. begin
  404. reset_reference(href1);
  405. href1.base:=procinfo.framepointer;
  406. href1.offset:=pvarsym(p)^.address+procinfo.call_offset;
  407. reset_reference(href2);
  408. href2.base:=procinfo.framepointer;
  409. href2.offset:=-pvarsym(p)^.localaddress;
  410. copyshortstring(href2,href1,pstringdef(pvarsym(p)^.definition)^.len,true);
  411. end
  412. else
  413. begin
  414. reset_reference(href1);
  415. href1.base:=procinfo.framepointer;
  416. href1.offset:=pvarsym(p)^.address+procinfo.call_offset;
  417. reset_reference(href2);
  418. href2.base:=procinfo.framepointer;
  419. href2.offset:=-pvarsym(p)^.localaddress;
  420. concatcopy(href1,href2,pvarsym(p)^.definition^.size,true,true);
  421. end;
  422. {$else}
  423. ;
  424. {$endif}
  425. exprasmlist:=oldexprasmlist;
  426. end;
  427. {$endif dummy}
  428. end;
  429. { wrappers for the methods, because TP doesn't know procedures }
  430. { of objects }
  431. procedure _copyopenarrays(s : pnamedindexobject);{$ifndef FPC}far;{$endif}
  432. begin
  433. cg^.g_copyopenarrays(s);
  434. end;
  435. procedure _finalize_data(s : pnamedindexobject);{$ifndef FPC}far;{$endif}
  436. begin
  437. cg^.g_finalize_data(s);
  438. end;
  439. procedure _incr_data(s : pnamedindexobject);{$ifndef FPC}far;{$endif}
  440. begin
  441. cg^.g_incr_data(psym(s));
  442. end;
  443. procedure _initialize_data(s : pnamedindexobject);{$ifndef FPC}far;{$endif}
  444. begin
  445. cg^.g_initialize_data(psym(s));
  446. end;
  447. { generates the entry code for a procedure }
  448. procedure tcg.g_entrycode(list : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
  449. stackframe:longint;var parasize:longint;var nostackframe:boolean;
  450. inlined : boolean);
  451. var
  452. hs : string;
  453. hp : pused_unit;
  454. initcode : taasmoutput;
  455. {$ifdef GDB}
  456. stab_function_name : Pai_stab_function_name;
  457. {$endif GDB}
  458. hr : treference;
  459. r : tregister;
  460. begin
  461. { Align }
  462. if (not inlined) then
  463. begin
  464. { gprof uses 16 byte granularity !! }
  465. if (cs_profile in aktmoduleswitches) then
  466. list^.insert(new(pai_align,init_op(16,$90)))
  467. else
  468. if not(cs_littlesize in aktglobalswitches) then
  469. list^.insert(new(pai_align,init(4)));
  470. end;
  471. { save registers on cdecl }
  472. if ((aktprocsym^.definition^.options and pocdecl)<>0) then
  473. begin
  474. for r:=firstreg to lastreg do
  475. begin
  476. if (r in registers_saved_on_cdecl) then
  477. if (r in general_registers) then
  478. begin
  479. if not(r in tg.unusedregsint) then
  480. a_push_reg(list,r)
  481. end
  482. else
  483. a_push_reg(list,r);
  484. end;
  485. end;
  486. { omit stack frame ? }
  487. if not inlined then
  488. if procinfo.framepointer=stack_pointer then
  489. begin
  490. CGMessage(cg_d_stackframe_omited);
  491. nostackframe:=true;
  492. if (aktprocsym^.definition^.options and (pounitinit or poproginit or pounitfinalize)<>0) then
  493. parasize:=0
  494. else
  495. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset-4;
  496. end
  497. else
  498. begin
  499. if (aktprocsym^.definition^.options and (pounitinit or poproginit or pounitfinalize)<>0) then
  500. parasize:=0
  501. else
  502. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset-8;
  503. nostackframe:=false;
  504. if (aktprocsym^.definition^.options and pointerrupt)<>0 then
  505. g_interrupt_stackframe_entry(list);
  506. g_stackframe_entry(list,stackframe);
  507. if (cs_check_stack in aktlocalswitches) and
  508. (tf_supports_stack_checking in target_info.flags) then
  509. g_stackcheck(@initcode,stackframe);
  510. end;
  511. if cs_profile in aktmoduleswitches then
  512. g_profilecode(@initcode);
  513. if (not inlined) and ((aktprocsym^.definition^.options and poproginit)<>0) then
  514. begin
  515. { needs the target a console flags ? }
  516. if tf_needs_isconsole in target_info.flags then
  517. begin
  518. hr.symbol:=newasmsymbol('U_'+target_info.system_unit+'_ISCONSOLE');
  519. if apptype=at_cui then
  520. a_load_const8_ref(list,1,hr)
  521. else
  522. a_load_const8_ref(list,0,hr);
  523. dispose(hr.symbol,done);
  524. end;
  525. hp:=pused_unit(usedunits.first);
  526. while assigned(hp) do
  527. begin
  528. { call the unit init code and make it external }
  529. if (hp^.u^.flags and uf_init)<>0 then
  530. a_call_name_ext(list,
  531. 'INIT$$'+hp^.u^.modulename^,0);
  532. hp:=Pused_unit(hp^.next);
  533. end;
  534. end;
  535. { a constructor needs a help procedure }
  536. if (aktprocsym^.definition^.options and poconstructor)<>0 then
  537. begin
  538. if procinfo._class^.isclass then
  539. begin
  540. list^.insert(new(pai386,op_cond_sym(A_Jcc,C_Z,S_NO,quickexitlabel)));
  541. list^.insert(new(pai386,op_sym(A_CALL,S_NO,newasmsymbol('FPC_NEW_CLASS'))));
  542. end
  543. else
  544. begin
  545. {
  546. list^.insert(new(pai_labeled,init(A_JZ,quickexitlabel)));
  547. list^.insert(new(pai386,op_csymbol(A_CALL,S_NO,
  548. newcsymbol('FPC_HELP_CONSTRUCTOR',0))));
  549. list^.insert(new(pai386,op_const_reg(A_MOV,S_L,procinfo._class^.vmt_offset,R_EDI)));
  550. concat_external('FPC_HELP_CONSTRUCTOR',EXT_NEAR);
  551. }
  552. end;
  553. end;
  554. {$ifdef GDB}
  555. if (cs_debuginfo in aktmoduleswitches) then
  556. list^.insert(new(pai_force_line,init));
  557. {$endif GDB}
  558. { initialize return value }
  559. if is_ansistring(procinfo.retdef) or
  560. is_widestring(procinfo.retdef) then
  561. begin
  562. reset_reference(hr);
  563. hr.offset:=procinfo.retoffset;
  564. hr.base:=procinfo.framepointer;
  565. a_load_const32_ref(list,0,hr);
  566. end;
  567. { generate copies of call by value parameters }
  568. if (aktprocsym^.definition^.options and poassembler=0) then
  569. begin
  570. {$ifndef VALUEPARA}
  571. aktprocsym^.definition^.parast^.foreach({$ifdef FPC}@{$endif FPC}_copyopenarrays);
  572. {$else}
  573. aktprocsym^.definition^.parast^.foreach({$ifdef FPC}@{$endif FPC}_copyvalueparas);
  574. {$endif}
  575. end;
  576. { initialisizes local data }
  577. aktprocsym^.definition^.localst^.foreach({$ifdef FPC}@{$endif FPC}_initialize_data);
  578. { add a reference to all call by value/const parameters }
  579. aktprocsym^.definition^.parast^.foreach({$ifdef FPC}@{$endif FPC}_incr_data);
  580. if (cs_profile in aktmoduleswitches) or
  581. (aktprocsym^.definition^.owner^.symtabletype=globalsymtable) or
  582. (assigned(procinfo._class) and (procinfo._class^.owner^.symtabletype=globalsymtable)) then
  583. make_global:=true;
  584. if not inlined then
  585. begin
  586. hs:=proc_names.get;
  587. {$ifdef GDB}
  588. if (cs_debuginfo in aktmoduleswitches) and target_os.use_function_relative_addresses then
  589. stab_function_name := new(pai_stab_function_name,init(strpnew(hs)));
  590. {$endif GDB}
  591. { insert the names for the procedure }
  592. while hs<>'' do
  593. begin
  594. if make_global then
  595. exprasmlist^.insert(new(pai_symbol,initname_global(hs,0)))
  596. else
  597. exprasmlist^.insert(new(pai_symbol,initname(hs,0)));
  598. {$ifdef GDB}
  599. if (cs_debuginfo in aktmoduleswitches) then
  600. begin
  601. if target_os.use_function_relative_addresses then
  602. list^.insert(new(pai_stab_function_name,init(strpnew(hs))));
  603. end;
  604. {$endif GDB}
  605. hs:=proc_names.get;
  606. end;
  607. end;
  608. {$ifdef GDB}
  609. if (not inlined) and (cs_debuginfo in aktmoduleswitches) then
  610. begin
  611. if target_os.use_function_relative_addresses then
  612. list^.insert(stab_function_name);
  613. if make_global or ((procinfo.flags and pi_is_global) <> 0) then
  614. aktprocsym^.is_global := True;
  615. list^.insert(new(pai_stabs,init(aktprocsym^.stabstring)));
  616. aktprocsym^.isstabwritten:=true;
  617. end;
  618. {$endif GDB}
  619. end;
  620. procedure tcg.g_exitcode(list : paasmoutput;parasize:longint;nostackframe,inlined:boolean);
  621. {$ifdef GDB}
  622. var
  623. mangled_length : longint;
  624. p : pchar;
  625. {$endif GDB}
  626. begin
  627. {$ifdef dummy}
  628. { !!!! insert there automatic destructors }
  629. curlist:=list;
  630. if aktexitlabel^.is_used then
  631. list^.insert(new(pai_label,init(aktexitlabel)));
  632. { call the destructor help procedure }
  633. if (aktprocsym^.definition^.options and podestructor)<>0 then
  634. begin
  635. if procinfo._class^.isclass then
  636. begin
  637. list^.insert(new(pai386,op_csymbol(A_CALL,S_NO,
  638. newcsymbol('FPC_DISPOSE_CLASS',0))));
  639. concat_external('FPC_DISPOSE_CLASS',EXT_NEAR);
  640. end
  641. else
  642. begin
  643. list^.insert(new(pai386,op_csymbol(A_CALL,S_NO,
  644. newcsymbol('FPC_HELP_DESTRUCTOR',0))));
  645. list^.insert(new(pai386,op_const_reg(A_MOV,S_L,procinfo._class^.vmt_offset,R_EDI)));
  646. concat_external('FPC_HELP_DESTRUCTOR',EXT_NEAR);
  647. end;
  648. end;
  649. { finalize local data }
  650. aktprocsym^.definition^.localst^.foreach({$ifdef FPC}@{$endif FPC}finalize_data);
  651. { finalize paras data }
  652. if assigned(aktprocsym^.definition^.parast) then
  653. aktprocsym^.definition^.parast^.foreach({$ifdef FPC}@{$endif FPC}finalize_data);
  654. { call __EXIT for main program }
  655. if (not DLLsource) and (not inlined) and ((aktprocsym^.definition^.options and poproginit)<>0) then
  656. begin
  657. list^.concat(new(pai386,op_csymbol(A_CALL,S_NO,newcsymbol('FPC_DO_EXIT',0))));
  658. concat_external('FPC_DO_EXIT',EXT_NEAR);
  659. end;
  660. { handle return value }
  661. if (aktprocsym^.definition^.options and poassembler)=0 then
  662. if (aktprocsym^.definition^.options and poconstructor)=0 then
  663. handle_return_value(list,inlined)
  664. else
  665. begin
  666. { successful constructor deletes the zero flag }
  667. { and returns self in eax }
  668. list^.concat(new(pai_label,init(quickexitlabel)));
  669. { eax must be set to zero if the allocation failed !!! }
  670. list^.concat(new(pai386,op_reg_reg(A_MOV,S_L,R_ESI,R_EAX)));
  671. list^.concat(new(pai386,op_reg_reg(A_OR,S_L,R_EAX,R_EAX)));
  672. end;
  673. { stabs uses the label also ! }
  674. if aktexit2label^.is_used or
  675. ((cs_debuginfo in aktmoduleswitches) and not inlined) then
  676. list^.concat(new(pai_label,init(aktexit2label)));
  677. { gives problems for long mangled names }
  678. {list^.concat(new(pai_symbol,init(aktprocsym^.definition^.mangledname+'_end')));}
  679. { should we restore edi ? }
  680. { for all i386 gcc implementations }
  681. if ((aktprocsym^.definition^.options and pocdecl)<>0) then
  682. begin
  683. list^.insert(new(pai386,op_reg(A_POP,S_L,R_EDI)));
  684. list^.insert(new(pai386,op_reg(A_POP,S_L,R_ESI)));
  685. if (aktprocsym^.definition^.usedregisters and ($80 shr byte(R_EBX)))<>0 then
  686. list^.insert(new(pai386,op_reg(A_POP,S_L,R_EBX)));
  687. { here we could reset R_EBX
  688. but that is risky because it only works
  689. if genexitcode is called after genentrycode
  690. so lets skip this for the moment PM
  691. aktprocsym^.definition^.usedregisters:=
  692. aktprocsym^.definition^.usedregisters or not ($80 shr byte(R_EBX));
  693. }
  694. end;
  695. if not(nostackframe) and not inlined then
  696. list^.concat(new(pai386,op_none(A_LEAVE,S_NO)));
  697. { parameters are limited to 65535 bytes because }
  698. { ret allows only imm16 }
  699. if (parasize>65535) and not(aktprocsym^.definition^.options and poclearstack<>0) then
  700. CGMessage(cg_e_parasize_too_big);
  701. { at last, the return is generated }
  702. if not inlined then
  703. if (aktprocsym^.definition^.options and pointerrupt)<>0 then
  704. generate_interrupt_stackframe_exit
  705. else
  706. begin
  707. {Routines with the poclearstack flag set use only a ret.}
  708. { also routines with parasize=0 }
  709. if (parasize=0) or (aktprocsym^.definition^.options and poclearstack<>0) then
  710. list^.concat(new(pai386,op_none(A_RET,S_NO)))
  711. else
  712. list^.concat(new(pai386,op_const(A_RET,S_NO,parasize)));
  713. end;
  714. {$ifdef GDB}
  715. if (cs_debuginfo in aktmoduleswitches) and not inlined then
  716. begin
  717. aktprocsym^.concatstabto(list);
  718. if assigned(procinfo._class) then
  719. list^.concat(new(pai_stabs,init(strpnew(
  720. '"$t:v'+procinfo._class^.numberstring+'",'+
  721. tostr(N_PSYM)+',0,0,'+tostr(procinfo.esi_offset)))));
  722. if (porddef(aktprocsym^.definition^.retdef) <> voiddef) then
  723. if ret_in_param(aktprocsym^.definition^.retdef) then
  724. list^.concat(new(pai_stabs,init(strpnew(
  725. '"'+aktprocsym^.name+':X*'+aktprocsym^.definition^.retdef^.numberstring+'",'+
  726. tostr(N_PSYM)+',0,0,'+tostr(procinfo.retoffset)))))
  727. else
  728. list^.concat(new(pai_stabs,init(strpnew(
  729. '"'+aktprocsym^.name+':X'+aktprocsym^.definition^.retdef^.numberstring+'",'+
  730. tostr(N_PSYM)+',0,0,'+tostr(procinfo.retoffset)))));
  731. mangled_length:=length(aktprocsym^.definition^.mangledname);
  732. getmem(p,mangled_length+50);
  733. strpcopy(p,'192,0,0,');
  734. strpcopy(strend(p),aktprocsym^.definition^.mangledname);
  735. list^.concat(new(pai_stabn,init(strnew(p))));
  736. {list^.concat(new(pai_stabn,init(strpnew('192,0,0,'
  737. +aktprocsym^.definition^.mangledname))));
  738. p[0]:='2';p[1]:='2';p[2]:='4';
  739. strpcopy(strend(p),'_end');}
  740. freemem(p,mangled_length+50);
  741. list^.concat(new(pai_stabn,init(
  742. strpnew('224,0,0,'+lab2str(aktexit2label)))));
  743. { strpnew('224,0,0,'
  744. +aktprocsym^.definition^.mangledname+'_end'))));}
  745. end;
  746. {$endif GDB}
  747. curlist:=nil;
  748. {$endif dummy}
  749. end;
  750. {*****************************************************************************
  751. some abstract definitions
  752. ****************************************************************************}
  753. procedure tcg.a_push_reg(list : paasmoutput;r : tregister);
  754. begin
  755. abstract;
  756. end;
  757. procedure tcg.a_call_name(list : paasmoutput;const s : string;
  758. offset : longint);
  759. begin
  760. abstract;
  761. end;
  762. procedure tcg.a_load_const8_ref(list : paasmoutput;b : byte;const ref : treference);
  763. begin
  764. abstract;
  765. end;
  766. procedure tcg.a_load_const16_ref(list : paasmoutput;w : word;const ref : treference);
  767. begin
  768. abstract;
  769. end;
  770. procedure tcg.a_load_const32_ref(list : paasmoutput;l : longint;const ref : treference);
  771. begin
  772. abstract;
  773. end;
  774. procedure tcg.a_load_const64_ref(list : paasmoutput;q : qword;const ref : treference);
  775. begin
  776. abstract;
  777. end;
  778. procedure tcg.g_stackframe_entry(list : paasmoutput;localsize : longint);
  779. begin
  780. abstract;
  781. end;
  782. procedure tcg.g_maybe_loadself(list : paasmoutput);
  783. begin
  784. abstract;
  785. end;
  786. end.
  787. {
  788. $Log$
  789. Revision 1.8 1999-08-02 17:14:07 florian
  790. + changed the temp. generator to an object
  791. Revision 1.7 1999/08/01 23:05:55 florian
  792. * changes to compile with FPC
  793. Revision 1.6 1999/08/01 18:22:33 florian
  794. * made it again compilable
  795. Revision 1.5 1999/01/23 23:29:46 florian
  796. * first running version of the new code generator
  797. * when compiling exceptions under Linux fixed
  798. Revision 1.4 1999/01/13 22:52:36 florian
  799. + YES, finally the new code generator is compilable, but it doesn't run yet :(
  800. Revision 1.3 1998/12/26 15:20:30 florian
  801. + more changes for the new version
  802. Revision 1.2 1998/12/15 22:18:55 florian
  803. * some code added
  804. Revision 1.1 1998/12/15 16:32:58 florian
  805. + first version, derived from old routines
  806. }