cgobj.pas 38 KB

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