cgobj.pas 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  1. {
  2. $Id$
  3. Copyright (c) 1993-99 by Florian Klaempfl
  4. Member of the Free Pascal development team
  5. This unit implements the basic code generator object
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit cgobj;
  20. interface
  21. uses
  22. cobjects,aasm,symtable,symconst,cpuasm,cpubase,cgbase,cpuinfo;
  23. type
  24. qword = comp;
  25. pcg = ^tcg;
  26. tcg = object
  27. scratch_register_array_pointer : aword;
  28. unusedscratchregisters : tregisterset;
  29. {************************************************}
  30. { basic routines }
  31. constructor init;
  32. destructor done;virtual;
  33. procedure a_label(list : paasmoutput;l : pasmlabel);virtual;
  34. { allocates register r by inserting a pai_realloc record }
  35. procedure a_reg_alloc(list : paasmoutput;r : tregister);
  36. { deallocates register r by inserting a pa_regdealloc record}
  37. procedure a_reg_dealloc(list : paasmoutput;r : tregister);
  38. { returns a register for use as scratch register }
  39. function get_scratch_reg(list : paasmoutput) : tregister;
  40. { releases a scratch register }
  41. procedure free_scratch_reg(list : paasmoutput;r : tregister);
  42. {************************************************}
  43. { code generation for subroutine entry/exit code }
  44. { helper routines }
  45. procedure g_initialize_data(list : paasmoutput;p : psym);
  46. procedure g_incr_data(list : paasmoutput;p : psym);
  47. procedure g_finalize_data(list : paasmoutput;p : pnamedindexobject);
  48. procedure g_copyvalueparas(list : paasmoutput;p : pnamedindexobject);
  49. procedure g_finalizetempansistrings(list : paasmoutput);
  50. { finalizes data of type t }
  51. { if is_already_ref is true then the routines assumes }
  52. { that r points to the data to finalizes }
  53. procedure g_finalize(list : paasmoutput;t : pdef;const ref : treference;is_already_ref : boolean);
  54. procedure g_entrycode(list : paasmoutput;
  55. const proc_names : tstringcontainer;make_global : boolean;
  56. stackframe : longint;var parasize : longint;
  57. var nostackframe : boolean;inlined : boolean);
  58. procedure g_exitcode(list : paasmoutput;parasize : longint;
  59. nostackframe,inlined : boolean);
  60. { string helper routines }
  61. procedure g_decrstrref(list : paasmoutput;const ref : treference;t : pdef);
  62. procedure g_removetemps(list : paasmoutput;p : plinkedlist);
  63. { passing parameters, per default the parameter is pushed }
  64. { nr gives the number of the parameter (enumerated from }
  65. { left to right), this allows to move the parameter to }
  66. { register, if the cpu supports register calling }
  67. { conventions }
  68. procedure a_param_reg(list : paasmoutput;size : tcgsize;r : tregister;nr : longint);virtual;
  69. procedure a_param_const(list : paasmoutput;size : tcgsize;a : aword;nr : longint);virtual;
  70. procedure a_param_ref(list : paasmoutput;size : tcgsize;const r : treference;nr : longint);virtual;
  71. procedure a_paramaddr_ref(list : paasmoutput;const r : treference;nr : longint);virtual;
  72. {**********************************}
  73. { these methods must be overriden: }
  74. { Remarks:
  75. * If a method specifies a size you have only to take care
  76. of that number of bits, i.e. load_const_reg with OP_8 must
  77. only load the lower 8 bit of the specified register
  78. the rest of the register can be undefined
  79. if necessary the compiler will call a method
  80. to zero or sign extend the register
  81. * The a_load_XX_XX with OP_64 needn't to be
  82. implemented for 32 bit
  83. processors, the code generator takes care of that
  84. * the addr size is for work with the natural pointer
  85. size
  86. * the procedures without fpu/mm are only for integer usage
  87. * normally the first location is the source and the
  88. second the destination
  89. }
  90. procedure a_call_name(list : paasmoutput;const s : string;
  91. offset : longint);virtual;
  92. { move instructions }
  93. procedure a_load_const_reg(list : paasmoutput;size : tcgsize;a : aword;register : tregister);virtual;
  94. procedure a_load_reg_ref(list : paasmoutput;size : tcgsize;register : tregister;const ref : treference);virtual;
  95. procedure a_load_ref_reg(list : paasmoutput;size : tcgsize;const ref : treference;register : tregister);virtual;
  96. procedure a_load_reg_reg(list : paasmoutput;size : tcgsize;reg1,reg2 : tregister);virtual;
  97. { comparison operations }
  98. procedure a_cmp_reg_const_label(list : paasmoutput;size : tcgsize;cmp_op : topcmp;b : byte;reg : tregister;
  99. l : pasmlabel);virtual;
  100. procedure a_cmp_reg_reg_label(list : paasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : pasmlabel);
  101. procedure a_cmp_reg_ref_label(list : paasmoutput;size : tcgsize;cmp_op : topcmp;reg : tregister;l : pasmlabel);
  102. procedure a_cmp_ref_const_label(list : paasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  103. l : pasmlabel);
  104. procedure a_loadaddress_ref_reg(list : paasmoutput;const ref : treference;r : tregister);virtual;
  105. procedure g_stackframe_entry(list : paasmoutput;localsize : longint);virtual;
  106. { restores the frame pointer at procedure exit, for the }
  107. { i386 it generates a simple leave }
  108. procedure g_restore_frame_pointer(list : paasmoutput);virtual;
  109. { some processors like the PPC doesn't allow to change the stack in }
  110. { a procedure, so we need to maintain an extra stack for the }
  111. { result values of setjmp in exception code }
  112. { this two procedures are for pushing an exception value, }
  113. { they can use the scratch registers }
  114. procedure g_push_exception_value_reg(list : paasmoutput;reg : tregister);virtual;
  115. procedure g_push_exception_value_const(list : paasmoutput;reg : tregister);virtual;
  116. { that procedure pops a exception value }
  117. procedure g_pop_exception_value_reg(list : paasmoutput;reg : tregister);virtual;
  118. procedure g_return_from_proc(list : paasmoutput;parasize : aword);virtual;
  119. {********************************************************}
  120. { these methods can be overriden for extra functionality }
  121. { the following methods do nothing: }
  122. procedure g_interrupt_stackframe_entry(list : paasmoutput);virtual;
  123. procedure g_interrupt_stackframe_exit(list : paasmoutput);virtual;
  124. procedure g_profilecode(list : paasmoutput);virtual;
  125. procedure g_stackcheck(list : paasmoutput;stackframesize : longint);virtual;
  126. procedure a_load_const_ref(list : paasmoutput;size : tcgsize;a : aword;const ref : treference);virtual;
  127. procedure g_maybe_loadself(list : paasmoutput);virtual;
  128. { uses the addr of ref as param, was emitpushreferenceaddr }
  129. procedure a_param_ref_addr(list : paasmoutput;r : treference;nr : longint);virtual;
  130. end;
  131. var
  132. cg : pcg; { this is the main code generator class }
  133. implementation
  134. uses
  135. globals,globtype,options,files,gdb,systems,
  136. ppu,verbose,types,tgobj,tgcpu;
  137. {*****************************************************************************
  138. basic functionallity
  139. ******************************************************************************}
  140. constructor tcg.init;
  141. var
  142. i : aword;
  143. begin
  144. scratch_register_array_pointer:=1;
  145. for i:=1 to max_scratch_regs do
  146. include(unusedscratchregisters,scratch_regs[i]);
  147. end;
  148. destructor tcg.done;
  149. begin
  150. end;
  151. procedure tcg.a_reg_alloc(list : paasmoutput;r : tregister);
  152. begin
  153. list^.concat(new(pairegalloc,alloc(r)));
  154. end;
  155. procedure tcg.a_reg_dealloc(list : paasmoutput;r : tregister);
  156. begin
  157. list^.concat(new(pairegalloc,dealloc(r)));
  158. end;
  159. procedure tcg.a_label(list : paasmoutput;l : pasmlabel);
  160. begin
  161. list^.concat(new(pai_label,init(l)));
  162. end;
  163. function tcg.get_scratch_reg(list : paasmoutput) : tregister;
  164. var
  165. r : tregister;
  166. i : aword;
  167. begin
  168. if unusedscratchregisters=[] then
  169. internalerror(68996);
  170. for i:=1 to max_scratch_regs do
  171. if scratch_regs[i] in unusedscratchregisters then
  172. begin
  173. r:=scratch_regs[i];
  174. break;
  175. end;
  176. exclude(unusedscratchregisters,r);
  177. inc(scratch_register_array_pointer);
  178. if scratch_register_array_pointer>max_scratch_regs then
  179. scratch_register_array_pointer:=1;
  180. a_reg_alloc(list,r);
  181. get_scratch_reg:=r;
  182. end;
  183. procedure tcg.free_scratch_reg(list : paasmoutput;r : tregister);
  184. begin
  185. include(unusedscratchregisters,r);
  186. a_reg_dealloc(list,r);
  187. end;
  188. {*****************************************************************************
  189. this methods must be overridden for extra functionality
  190. ******************************************************************************}
  191. procedure tcg.g_interrupt_stackframe_entry(list : paasmoutput);
  192. begin
  193. end;
  194. procedure tcg.g_interrupt_stackframe_exit(list : paasmoutput);
  195. begin
  196. end;
  197. procedure tcg.g_profilecode(list : paasmoutput);
  198. begin
  199. end;
  200. {*****************************************************************************
  201. for better code generation these methods should be overridden
  202. ******************************************************************************}
  203. procedure tcg.a_param_const(list : paasmoutput;size : tcgsize;a : aword;nr : longint);
  204. var
  205. hr : tregister;
  206. begin
  207. hr:=get_scratch_reg(list);
  208. a_load_const_reg(list,size,a,hr);
  209. a_param_reg(list,size,hr,nr);
  210. free_scratch_reg(list,hr);
  211. end;
  212. procedure tcg.a_param_ref(list : paasmoutput;size : tcgsize;const r : treference;nr : longint);
  213. var
  214. hr : tregister;
  215. begin
  216. hr:=get_scratch_reg(list);
  217. a_load_ref_reg(list,size,r,hr);
  218. a_param_reg(list,size,hr,nr);
  219. free_scratch_reg(list,hr);
  220. end;
  221. procedure tcg.a_param_ref_addr(list : paasmoutput;r : treference;nr : longint);
  222. var
  223. hr : tregister;
  224. begin
  225. hr:=get_scratch_reg(list);
  226. a_loadaddress_ref_reg(list,r,hr);
  227. a_param_reg(list,OS_ADDR,hr,nr);
  228. free_scratch_reg(list,hr);
  229. end;
  230. procedure tcg.g_stackcheck(list : paasmoutput;stackframesize : longint);
  231. begin
  232. a_param_const(list,OS_32,stackframesize,1);
  233. a_call_name(list,'FPC_STACKCHECK',0);
  234. end;
  235. procedure tcg.a_load_const_ref(list : paasmoutput;size : tcgsize;a : aword;const ref : treference);
  236. var
  237. hr : tregister;
  238. begin
  239. hr:=get_scratch_reg(list);
  240. a_load_const_reg(list,size,a,hr);
  241. a_load_reg_ref(list,size,hr,ref);
  242. a_reg_dealloc(list,hr);
  243. free_scratch_reg(list,hr);
  244. end;
  245. {*****************************************************************************
  246. String helper routines
  247. *****************************************************************************}
  248. procedure tcg.g_removetemps(list : paasmoutput;p : plinkedlist);
  249. var
  250. hp : ptemptodestroy;
  251. pushedregs : tpushed;
  252. begin
  253. hp:=ptemptodestroy(p^.first);
  254. if not(assigned(hp)) then
  255. exit;
  256. tg.pushusedregisters(pushedregs,$ff);
  257. while assigned(hp) do
  258. begin
  259. if is_ansistring(hp^.typ) then
  260. begin
  261. g_decrstrref(list,hp^.address,hp^.typ);
  262. tg.ungetiftemp(hp^.address);
  263. end;
  264. hp:=ptemptodestroy(hp^.next);
  265. end;
  266. tg.popusedregisters(pushedregs);
  267. end;
  268. procedure tcg.g_decrstrref(list : paasmoutput;const ref : treference;t : pdef);
  269. var
  270. pushedregs : tpushed;
  271. begin
  272. tg.pushusedregisters(pushedregs,$ff);
  273. a_param_ref_addr(list,ref,1);
  274. if is_ansistring(t) then
  275. a_call_name(list,'FPC_ANSISTR_DECR_REF',0)
  276. else if is_widestring(t) then
  277. a_call_name(list,'FPC_WIDESTR_DECR_REF',0)
  278. else internalerror(58993);
  279. tg.popusedregisters(pushedregs);
  280. end;
  281. {*****************************************************************************
  282. Code generation for subroutine entry- and exit code
  283. *****************************************************************************}
  284. procedure tcg.g_finalize(list : paasmoutput;t : pdef;const ref : treference;is_already_ref : boolean);
  285. var
  286. r : treference;
  287. begin
  288. if is_ansistring(t) or
  289. is_widestring(t) then
  290. begin
  291. g_decrstrref(list,ref,t);
  292. end
  293. else
  294. begin
  295. reset_reference(r);
  296. r.symbol:=t^.get_inittable_label;
  297. a_param_ref_addr(list,r,2);
  298. if is_already_ref then
  299. a_paramaddr_ref(list,ref,1)
  300. else
  301. a_param_ref_addr(list,ref,1);
  302. a_call_name(list,'FPC_FINALIZE',0);
  303. end;
  304. end;
  305. { generates the code for initialisation of local data }
  306. procedure tcg.g_initialize_data(list : paasmoutput;p : psym);
  307. begin
  308. runerror(255);
  309. end;
  310. { generates the code for incrementing the reference count of parameters }
  311. procedure tcg.g_incr_data(list : paasmoutput;p : psym);
  312. var
  313. hr : treference;
  314. begin
  315. if (psym(p)^.typ=varsym) and
  316. not((pvarsym(p)^.definition^.deftype=objectdef) and
  317. pobjectdef(pvarsym(p)^.definition)^.is_class) and
  318. pvarsym(p)^.definition^.needs_inittable and
  319. ((pvarsym(p)^.varspez=vs_value)) then
  320. begin
  321. procinfo.flags:=procinfo.flags or pi_needs_implicit_finally;
  322. reset_reference(hr);
  323. hr.symbol:=pvarsym(p)^.definition^.get_inittable_label;
  324. a_param_ref_addr(list,hr,2);
  325. reset_reference(hr);
  326. hr.base:=procinfo.framepointer;
  327. hr.offset:=pvarsym(p)^.address+procinfo.call_offset;
  328. a_param_ref_addr(list,hr,1);
  329. reset_reference(hr);
  330. a_call_name(list,'FPC_ADDREF',0);
  331. end;
  332. end;
  333. { generates the code for finalisation of local data }
  334. procedure tcg.g_finalize_data(list : paasmoutput;p : pnamedindexobject);
  335. begin
  336. runerror(255);
  337. end;
  338. { generates the code to make local copies of the value parameters }
  339. procedure tcg.g_copyvalueparas(list : paasmoutput;p : pnamedindexobject);
  340. begin
  341. runerror(255);
  342. end;
  343. var
  344. _list : paasmoutput;
  345. { wrappers for the methods, because TP doesn't know procedures }
  346. { of objects }
  347. procedure _copyvalueparas(s : pnamedindexobject);{$ifndef FPC}far;{$endif}
  348. begin
  349. cg^.g_copyvalueparas(_list,s);
  350. end;
  351. procedure tcg.g_finalizetempansistrings(list : paasmoutput);
  352. var
  353. hp : ptemprecord;
  354. hr : treference;
  355. begin
  356. hp:=tg.templist;
  357. while assigned(hp) do
  358. begin
  359. if hp^.temptype in [tt_ansistring,tt_freeansistring] then
  360. begin
  361. procinfo.flags:=procinfo.flags or pi_needs_implicit_finally;
  362. reset_reference(hr);
  363. hr.base:=procinfo.framepointer;
  364. hr.offset:=hp^.pos;
  365. a_param_ref_addr(list,hr,1);
  366. a_call_name(list,'FPC_ANSISTR_DECR_REF',0);
  367. end;
  368. hp:=hp^.next;
  369. end;
  370. end;
  371. procedure _finalize_data(s : pnamedindexobject);{$ifndef FPC}far;{$endif}
  372. begin
  373. cg^.g_finalize_data(_list,s);
  374. end;
  375. procedure _incr_data(s : pnamedindexobject);{$ifndef FPC}far;{$endif}
  376. begin
  377. cg^.g_incr_data(_list,psym(s));
  378. end;
  379. procedure _initialize_data(s : pnamedindexobject);{$ifndef FPC}far;{$endif}
  380. begin
  381. cg^.g_initialize_data(_list,psym(s));
  382. end;
  383. { generates the entry code for a procedure }
  384. procedure tcg.g_entrycode(list : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
  385. stackframe:longint;var parasize:longint;var nostackframe:boolean;
  386. inlined : boolean);
  387. var
  388. hs : string;
  389. hp : pused_unit;
  390. initcode : taasmoutput;
  391. {$ifdef GDB}
  392. stab_function_name : Pai_stab_function_name;
  393. {$endif GDB}
  394. hr : treference;
  395. r : tregister;
  396. begin
  397. { Align }
  398. if (not inlined) then
  399. begin
  400. { gprof uses 16 byte granularity !! }
  401. if (cs_profile in aktmoduleswitches) then
  402. list^.insert(new(pai_align,init(16)))
  403. else
  404. if not(cs_littlesize in aktglobalswitches) then
  405. list^.insert(new(pai_align,init(4)));
  406. end;
  407. { save registers on cdecl }
  408. if (po_savestdregs in aktprocsym^.definition^.procoptions) then
  409. begin
  410. for r:=firstreg to lastreg do
  411. begin
  412. if (r in registers_saved_on_cdecl) then
  413. if (r in (tg.availabletempregsint+
  414. tg.availabletempregsfpu+
  415. tg.availabletempregsmm)) then
  416. begin
  417. if not(r in tg.usedinproc) then
  418. {!!!!!!!!!!!! a_push_reg(list,r) }
  419. end
  420. else
  421. {!!!!!!!! a_push_reg(list,r) };
  422. end;
  423. end;
  424. { omit stack frame ? }
  425. if not inlined then
  426. if procinfo.framepointer=stack_pointer then
  427. begin
  428. CGMessage(cg_d_stackframe_omited);
  429. nostackframe:=true;
  430. if (aktprocsym^.definition^.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
  431. parasize:=0
  432. else
  433. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset-pointersize;
  434. end
  435. else
  436. begin
  437. if (aktprocsym^.definition^.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
  438. parasize:=0
  439. else
  440. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset-pointersize*2;
  441. nostackframe:=false;
  442. if (po_interrupt in aktprocsym^.definition^.procoptions) then
  443. g_interrupt_stackframe_entry(list);
  444. g_stackframe_entry(list,stackframe);
  445. if (cs_check_stack in aktlocalswitches) and
  446. (tf_supports_stack_checking in target_info.flags) then
  447. g_stackcheck(@initcode,stackframe);
  448. end;
  449. if cs_profile in aktmoduleswitches then
  450. g_profilecode(@initcode);
  451. if (not inlined) and (aktprocsym^.definition^.proctypeoption in [potype_unitinit]) then
  452. begin
  453. { needs the target a console flags ? }
  454. if tf_needs_isconsole in target_info.flags then
  455. begin
  456. hr.symbol:=newasmsymbol('U_'+target_info.system_unit+'_ISCONSOLE');
  457. if apptype=at_cui then
  458. a_load_const_ref(list,OS_8,1,hr)
  459. else
  460. a_load_const_ref(list,OS_8,0,hr);
  461. dispose(hr.symbol,done);
  462. end;
  463. hp:=pused_unit(usedunits.first);
  464. while assigned(hp) do
  465. begin
  466. { call the unit init code and make it external }
  467. if (hp^.u^.flags and uf_init)<>0 then
  468. a_call_name(list,
  469. 'INIT$$'+hp^.u^.modulename^,0);
  470. hp:=Pused_unit(hp^.next);
  471. end;
  472. end;
  473. {$ifdef dummy}
  474. { a constructor needs a help procedure }
  475. if (aktprocsym^.definition^.options and poconstructor)<>0 then
  476. begin
  477. if procinfo._class^.isclass then
  478. begin
  479. list^.concat(new(pai386,op_sym(A_CALL,S_NO,newasmsymbol('FPC_NEW_CLASS'))));
  480. list^.concat(new(pai386,op_cond_sym(A_Jcc,C_Z,S_NO,quickexitlabel)));
  481. end
  482. else
  483. begin
  484. {
  485. list^.insert(new(pai_labeled,init(A_JZ,quickexitlabel)));
  486. list^.insert(new(pai386,op_csymbol(A_CALL,S_NO,
  487. newcsymbol('FPC_HELP_CONSTRUCTOR',0))));
  488. list^.insert(new(pai386,op_const_reg(A_MOV,S_L,procinfo._class^.vmt_offset,R_EDI)));
  489. concat_external('FPC_HELP_CONSTRUCTOR',EXT_NEAR);
  490. }
  491. end;
  492. end;
  493. {$endif dummy}
  494. {$ifdef GDB}
  495. if (cs_debuginfo in aktmoduleswitches) then
  496. list^.insert(new(pai_force_line,init));
  497. {$endif GDB}
  498. { initialize return value }
  499. if is_ansistring(procinfo.retdef) or
  500. is_widestring(procinfo.retdef) then
  501. begin
  502. reset_reference(hr);
  503. hr.offset:=procinfo.retoffset;
  504. hr.base:=procinfo.framepointer;
  505. a_load_const_ref(list,OS_32,0,hr);
  506. end;
  507. _list:=list;
  508. { generate copies of call by value parameters }
  509. if (po_assembler in aktprocsym^.definition^.procoptions) then
  510. aktprocsym^.definition^.parast^.foreach({$ifdef FPC}@{$endif FPC}_copyvalueparas);
  511. { initialisizes local data }
  512. aktprocsym^.definition^.localst^.foreach({$ifdef FPC}@{$endif FPC}_initialize_data);
  513. { add a reference to all call by value/const parameters }
  514. aktprocsym^.definition^.parast^.foreach({$ifdef FPC}@{$endif FPC}_incr_data);
  515. if (cs_profile in aktmoduleswitches) or
  516. (aktprocsym^.definition^.owner^.symtabletype=globalsymtable) or
  517. (assigned(procinfo._class) and (procinfo._class^.owner^.symtabletype=globalsymtable)) then
  518. make_global:=true;
  519. if not inlined then
  520. begin
  521. hs:=proc_names.get;
  522. {$ifdef GDB}
  523. if (cs_debuginfo in aktmoduleswitches) and target_os.use_function_relative_addresses then
  524. stab_function_name := new(pai_stab_function_name,init(strpnew(hs)));
  525. {$endif GDB}
  526. { insert the names for the procedure }
  527. while hs<>'' do
  528. begin
  529. if make_global then
  530. exprasmlist^.insert(new(pai_symbol,initname_global(hs,0)))
  531. else
  532. exprasmlist^.insert(new(pai_symbol,initname(hs,0)));
  533. {$ifdef GDB}
  534. if (cs_debuginfo in aktmoduleswitches) then
  535. begin
  536. if target_os.use_function_relative_addresses then
  537. list^.insert(new(pai_stab_function_name,init(strpnew(hs))));
  538. end;
  539. {$endif GDB}
  540. hs:=proc_names.get;
  541. end;
  542. end;
  543. {$ifdef GDB}
  544. if (not inlined) and (cs_debuginfo in aktmoduleswitches) then
  545. begin
  546. if target_os.use_function_relative_addresses then
  547. list^.insert(stab_function_name);
  548. if make_global or ((procinfo.flags and pi_is_global) <> 0) then
  549. aktprocsym^.is_global := True;
  550. list^.insert(new(pai_stabs,init(aktprocsym^.stabstring)));
  551. aktprocsym^.isstabwritten:=true;
  552. end;
  553. {$endif GDB}
  554. end;
  555. procedure tcg.g_exitcode(list : paasmoutput;parasize:longint;nostackframe,inlined:boolean);
  556. var
  557. {$ifdef GDB}
  558. mangled_length : longint;
  559. p : pchar;
  560. {$endif GDB}
  561. noreraiselabel : pasmlabel;
  562. hr : treference;
  563. r : tregister;
  564. begin
  565. if aktexitlabel^.is_used then
  566. list^.insert(new(pai_label,init(aktexitlabel)));
  567. { call the destructor help procedure }
  568. if (aktprocsym^.definition^.proctypeoption=potype_destructor) then
  569. begin
  570. if procinfo._class^.is_class then
  571. a_call_name(list,'FPC_DISPOSE_CLASS',0)
  572. else
  573. begin
  574. { vmt_offset_reg can be a scratch register, }
  575. { but it must be always the same }
  576. a_reg_alloc(list,vmt_offset_reg);
  577. a_load_const_reg(list,OS_32,procinfo._class^.vmt_offset,vmt_offset_reg);
  578. a_call_name(list,'FPC_HELP_DESTRUCTOR',0);
  579. a_reg_dealloc(list,vmt_offset_reg);
  580. end;
  581. end;
  582. { finalize temporary data }
  583. g_finalizetempansistrings(list);
  584. _list:=list;
  585. { finalize local data }
  586. aktprocsym^.definition^.localst^.foreach({$ifndef TP}@{$endif}_finalize_data);
  587. { finalize paras data }
  588. if assigned(aktprocsym^.definition^.parast) then
  589. aktprocsym^.definition^.parast^.foreach({$ifndef TP}@{$endif}_finalize_data);
  590. { do we need to handle exceptions because of ansi/widestrings ? }
  591. if (procinfo.flags and pi_needs_implicit_finally)<>0 then
  592. begin
  593. getlabel(noreraiselabel);
  594. a_call_name(list,'FPC_POPADDRSTACK',0);
  595. a_reg_alloc(list,accumulator);
  596. g_pop_exception_value_reg(list,accumulator);
  597. a_cmp_reg_const_label(list,OS_32,OC_EQ,0,accumulator,noreraiselabel);
  598. a_reg_dealloc(list,accumulator);
  599. { must be the return value finalized before reraising the exception? }
  600. if (procinfo.retdef<>pdef(voiddef)) and
  601. (procinfo.retdef^.needs_inittable) and
  602. ((procinfo.retdef^.deftype<>objectdef) or
  603. not(pobjectdef(procinfo.retdef)^.is_class)) then
  604. begin
  605. reset_reference(hr);
  606. hr.offset:=procinfo.retoffset;
  607. hr.base:=procinfo.framepointer;
  608. g_finalize(list,procinfo.retdef,hr,ret_in_param(procinfo.retdef));
  609. end;
  610. a_call_name(list,'FPC_RERAISE',0);
  611. a_label(list,noreraiselabel);
  612. end;
  613. { call __EXIT for main program }
  614. if (not DLLsource) and (not inlined) and (aktprocsym^.definition^.proctypeoption=potype_proginit) then
  615. a_call_name(list,'FPC_DO_EXIT',0);
  616. { handle return value }
  617. if not(po_assembler in aktprocsym^.definition^.procoptions) then
  618. if (aktprocsym^.definition^.proctypeoption<>potype_constructor) then
  619. { handle_return_value(inlined) }
  620. else
  621. begin
  622. { return self in EAX }
  623. a_label(list,quickexitlabel);
  624. a_reg_alloc(list,accumulator);
  625. a_load_reg_reg(list,OS_ADDR,self_pointer,accumulator);
  626. a_reg_dealloc(list,self_pointer);
  627. a_label(list,quickexitlabel);
  628. { we can't clear the zero flag because the Alpha }
  629. { for example doesn't have flags, we have to compare }
  630. { the accu. in the caller }
  631. end;
  632. { stabs uses the label also ! }
  633. if aktexit2label^.is_used or
  634. ((cs_debuginfo in aktmoduleswitches) and not inlined) then
  635. a_label(list,aktexit2label);
  636. {$ifdef dummy}
  637. { should we restore edi ? }
  638. { for all i386 gcc implementations }
  639. {!!!!!!!!!!! I don't know how to handle register saving yet }
  640. if (po_savestdregs in aktprocsym^.definition^.procoptions) then
  641. begin
  642. if (aktprocsym^.definition^.usedregisters and ($80 shr byte(R_EBX)))<>0 then
  643. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EBX)));
  644. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_ESI)));
  645. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EDI)));
  646. { here we could reset R_EBX
  647. but that is risky because it only works
  648. if genexitcode is called after genentrycode
  649. so lets skip this for the moment PM
  650. aktprocsym^.definition^.usedregisters:=
  651. aktprocsym^.definition^.usedregisters or not ($80 shr byte(R_EBX));
  652. }
  653. end;
  654. {$endif dummy}
  655. if not(nostackframe) and not inlined then
  656. g_restore_frame_pointer(list);
  657. { at last, the return is generated }
  658. if not inlined then
  659. if po_interrupt in aktprocsym^.definition^.procoptions then
  660. g_interrupt_stackframe_exit(list)
  661. else
  662. g_return_from_proc(list,parasize);
  663. list^.concat(new(pai_symbol_end,initname(aktprocsym^.definition^.mangledname)));
  664. {$ifdef GDB}
  665. if (cs_debuginfo in aktmoduleswitches) and not inlined then
  666. begin
  667. aktprocsym^.concatstabto(exprasmlist);
  668. if assigned(procinfo._class) then
  669. if (not assigned(procinfo.parent) or
  670. not assigned(procinfo.parent^._class)) then
  671. list^.concat(new(pai_stabs,init(strpnew(
  672. '"$t:v'+procinfo._class^.numberstring+'",'+
  673. tostr(N_PSYM)+',0,0,'+tostr(procinfo.selfpointer_offset)))))
  674. else
  675. list^.concat(new(pai_stabs,init(strpnew(
  676. '"$t:r'+procinfo._class^.numberstring+'",'+
  677. tostr(N_RSYM)+',0,0,'+tostr(GDB_i386index[R_ESI])))));
  678. if (pdef(aktprocsym^.definition^.retdef) <> pdef(voiddef)) then
  679. if ret_in_param(aktprocsym^.definition^.retdef) then
  680. list^.concat(new(pai_stabs,init(strpnew(
  681. '"'+aktprocsym^.name+':X*'+aktprocsym^.definition^.retdef^.numberstring+'",'+
  682. tostr(N_PSYM)+',0,0,'+tostr(procinfo.retoffset)))))
  683. else
  684. list^.concat(new(pai_stabs,init(strpnew(
  685. '"'+aktprocsym^.name+':X'+aktprocsym^.definition^.retdef^.numberstring+'",'+
  686. tostr(N_PSYM)+',0,0,'+tostr(procinfo.retoffset)))));
  687. mangled_length:=length(aktprocsym^.definition^.mangledname);
  688. getmem(p,mangled_length+50);
  689. strpcopy(p,'192,0,0,');
  690. strpcopy(strend(p),aktprocsym^.definition^.mangledname);
  691. exprasmlist^.concat(new(pai_stabn,init(strnew(p))));
  692. {list^.concat(new(pai_stabn,init(strpnew('192,0,0,'
  693. +aktprocsym^.definition^.mangledname))));
  694. p[0]:='2';p[1]:='2';p[2]:='4';
  695. strpcopy(strend(p),'_end');}
  696. freemem(p,mangled_length+50);
  697. exprasmlist^.concat(new(pai_stabn,init(
  698. strpnew('224,0,0,'+aktexit2label^.name))));
  699. { strpnew('224,0,0,'
  700. +aktprocsym^.definition^.mangledname+'_end'))));}
  701. end;
  702. {$endif GDB}
  703. end;
  704. {*****************************************************************************
  705. some abstract definitions
  706. ****************************************************************************}
  707. procedure tcg.a_call_name(list : paasmoutput;const s : string;
  708. offset : longint);
  709. begin
  710. abstract;
  711. end;
  712. procedure tcg.g_stackframe_entry(list : paasmoutput;localsize : longint);
  713. begin
  714. abstract;
  715. end;
  716. procedure tcg.g_maybe_loadself(list : paasmoutput);
  717. begin
  718. abstract;
  719. end;
  720. procedure tcg.g_restore_frame_pointer(list : paasmoutput);
  721. begin
  722. abstract;
  723. end;
  724. procedure g_return_from_proc(list : paasmoutput;parasize : aword);
  725. begin
  726. abstract;
  727. end;
  728. procedure tcg.a_loadaddress_ref_reg(list : paasmoutput;const ref : treference;r : tregister);
  729. begin
  730. abstract;
  731. end;
  732. procedure tcg.g_push_exception_value_reg(list : paasmoutput;reg : tregister);
  733. begin
  734. abstract;
  735. end;
  736. procedure tcg.g_push_exception_value_const(list : paasmoutput;reg : tregister);
  737. begin
  738. abstract;
  739. end;
  740. procedure tcg.g_pop_exception_value_reg(list : paasmoutput;reg : tregister);
  741. begin
  742. abstract;
  743. end;
  744. procedure tcg.a_load_const_reg(list : paasmoutput;size : tcgsize;a : aword;register : tregister);
  745. begin
  746. abstract;
  747. end;
  748. procedure tcg.a_load_reg_ref(list : paasmoutput;size : tcgsize;register : tregister;const ref : treference);
  749. begin
  750. abstract;
  751. end;
  752. procedure tcg.a_load_ref_reg(list : paasmoutput;size : tcgsize;const ref : treference;register : tregister);
  753. begin
  754. abstract;
  755. end;
  756. procedure tcg.a_load_reg_reg(list : paasmoutput;size : tcgsize;reg1,reg2 : tregister);
  757. begin
  758. abstract;
  759. end;
  760. procedure tcg.a_cmp_reg_const_label(list : paasmoutput;size : tcgsize;cmp_op : topcmp;b : byte;reg : tregister;
  761. l : pasmlabel);
  762. begin
  763. abstract;
  764. end;
  765. procedure tcg.a_cmp_reg_reg_label(list : paasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : pasmlabel);
  766. begin
  767. abstract;
  768. end;
  769. procedure tcg.a_cmp_reg_ref_label(list : paasmoutput;size : tcgsize;cmp_op : topcmp;reg : tregister;l : pasmlabel);
  770. begin
  771. abstract;
  772. end;
  773. procedure tcg.a_cmp_ref_const_label(list : paasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  774. l : pasmlabel);
  775. begin
  776. abstract;
  777. end;
  778. procedure tcg.g_return_from_proc(list : paasmoutput;parasize : aword);
  779. begin
  780. abstract;
  781. end;
  782. procedure tcg.a_param_reg(list : paasmoutput;size : tcgsize;r : tregister;nr : longint);
  783. begin
  784. abstract;
  785. end;
  786. procedure tcg.a_paramaddr_ref(list : paasmoutput;const r : treference;nr : longint);
  787. begin
  788. abstract;
  789. end;
  790. end.
  791. {
  792. $Log$
  793. Revision 1.15 1999-08-06 15:53:50 florian
  794. * made the alpha version compilable
  795. Revision 1.14 1999/08/06 14:15:51 florian
  796. * made the alpha version compilable
  797. Revision 1.13 1999/08/06 13:26:50 florian
  798. * more changes ...
  799. Revision 1.12 1999/08/05 17:10:56 florian
  800. * some more additions, especially procedure
  801. exit code generation
  802. Revision 1.11 1999/08/05 14:58:11 florian
  803. * some fixes for the floating point registers
  804. * more things for the new code generator
  805. Revision 1.10 1999/08/04 00:23:52 florian
  806. * renamed i386asm and i386base to cpuasm and cpubase
  807. Revision 1.9 1999/08/02 23:13:21 florian
  808. * more changes to compile for the Alpha
  809. Revision 1.8 1999/08/02 17:14:07 florian
  810. + changed the temp. generator to an object
  811. Revision 1.7 1999/08/01 23:05:55 florian
  812. * changes to compile with FPC
  813. Revision 1.6 1999/08/01 18:22:33 florian
  814. * made it again compilable
  815. Revision 1.5 1999/01/23 23:29:46 florian
  816. * first running version of the new code generator
  817. * when compiling exceptions under Linux fixed
  818. Revision 1.4 1999/01/13 22:52:36 florian
  819. + YES, finally the new code generator is compilable, but it doesn't run yet :(
  820. Revision 1.3 1998/12/26 15:20:30 florian
  821. + more changes for the new version
  822. Revision 1.2 1998/12/15 22:18:55 florian
  823. * some code added
  824. Revision 1.1 1998/12/15 16:32:58 florian
  825. + first version, derived from old routines
  826. }