cgobj.pas 33 KB

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