cgobj.pas 41 KB

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