hcodegen.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. {
  2. $Id$
  3. Copyright (c) 1996-98 by Florian Klaempfl
  4. This unit exports some help routines for the code generation
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit hcodegen;
  19. interface
  20. uses
  21. aasm,tree,symtable
  22. {$ifdef i386}
  23. ,i386
  24. {$endif}
  25. {$ifdef m68k}
  26. ,m68k
  27. {$endif}
  28. ;
  29. const
  30. pi_uses_asm = $1; { set, if the procedure uses asm }
  31. pi_is_global = $2; { set, if the procedure is exported by an unit }
  32. pi_do_call = $4; { set, if the procedure does a call }
  33. pi_operator = $8; { set, if the procedure is an operator }
  34. pi_C_import = $10; { set, if the procedure is an external C function }
  35. type
  36. pprocinfo = ^tprocinfo;
  37. tprocinfo = record
  38. { pointer to parent in nested procedures }
  39. parent : pprocinfo;
  40. { current class, if we are in a method }
  41. _class : pobjectdef;
  42. { return type }
  43. retdef : pdef;
  44. { frame pointer offset }
  45. framepointer_offset : longint;
  46. { self pointer offset }
  47. ESI_offset : longint;
  48. { result value offset }
  49. retoffset : longint;
  50. { firsttemp position }
  51. firsttemp : longint;
  52. funcret_is_valid : boolean;
  53. { parameter offset }
  54. call_offset : longint;
  55. { some collected informations about the procedure }
  56. { see pi_xxxx above }
  57. flags : longint;
  58. { register used as frame pointer }
  59. framepointer : tregister;
  60. { true, if the procedure is exported by an unit }
  61. globalsymbol : boolean;
  62. { true, if the procedure should be exported (only OS/2) }
  63. exported : boolean;
  64. { code for the current procedure }
  65. aktproccode,aktentrycode,
  66. aktexitcode,aktlocaldata : paasmoutput;
  67. { local data is used for smartlink }
  68. end;
  69. var
  70. { info about the current sub routine }
  71. procinfo : tprocinfo;
  72. { labels for BREAK and CONTINUE }
  73. aktbreaklabel,aktcontinuelabel : plabel;
  74. { label when the result is true or false }
  75. truelabel,falselabel : plabel;
  76. { label to leave the sub routine }
  77. aktexitlabel : plabel;
  78. { also an exit label, only used we need to clear only the stack }
  79. aktexit2label : plabel;
  80. { only used in constructor for fail or if getmem fails }
  81. quickexitlabel : plabel;
  82. { Boolean, wenn eine loadn kein Assembler erzeugt hat }
  83. simple_loadn : boolean;
  84. { tries to hold the amount of times which the current tree is processed }
  85. t_times : longint;
  86. { true, if an error while code generation occurs }
  87. codegenerror : boolean;
  88. { initialize respectively terminates the code generator }
  89. { for a new module or procedure }
  90. procedure codegen_doneprocedure;
  91. procedure codegen_donemodule;
  92. procedure codegen_newmodule;
  93. procedure codegen_newprocedure;
  94. { counts the labels }
  95. function case_count_labels(root : pcaserecord) : longint;
  96. { searches the highest label }
  97. function case_get_max(root : pcaserecord) : longint;
  98. { searches the lowest label }
  99. function case_get_min(root : pcaserecord) : longint;
  100. { concates/inserts the ASCII string to the data segment }
  101. procedure generate_ascii(const hs : string);
  102. procedure generate_ascii_insert(const hs : string);
  103. { concates/inserts the ASCII string from pchar to the data segment }
  104. { WARNING : if hs has no #0 and strlen(hs)=length }
  105. { the terminal zero is not written }
  106. procedure generate_pascii(hs : pchar;length : longint);
  107. procedure generate_pascii_insert(hs : pchar;length : longint);
  108. { convert/concats a label for constants in the consts section }
  109. function constlabel2str(p:plabel;ctype:tconsttype):string;
  110. procedure concat_constlabel(p:plabel;ctype:tconsttype);
  111. implementation
  112. uses
  113. cobjects,globals,files,strings;
  114. {*****************************************************************************
  115. initialize/terminate the codegen for procedure and modules
  116. *****************************************************************************}
  117. procedure codegen_newprocedure;
  118. begin
  119. aktbreaklabel:=nil;
  120. aktcontinuelabel:=nil;
  121. { aktexitlabel:=0; is store in oldaktexitlabel
  122. so it must not be reset to zero before this storage !}
  123. { the type of this lists isn't important }
  124. { because the code of this lists is }
  125. { copied to the code segment }
  126. procinfo.aktentrycode:=new(paasmoutput,init);
  127. procinfo.aktexitcode:=new(paasmoutput,init);
  128. procinfo.aktproccode:=new(paasmoutput,init);
  129. procinfo.aktlocaldata:=new(paasmoutput,init);
  130. end;
  131. procedure codegen_doneprocedure;
  132. begin
  133. dispose(procinfo.aktentrycode,done);
  134. dispose(procinfo.aktexitcode,done);
  135. dispose(procinfo.aktproccode,done);
  136. dispose(procinfo.aktlocaldata,done);
  137. end;
  138. procedure codegen_newmodule;
  139. begin
  140. exprasmlist:=new(paasmoutput,init);
  141. datasegment:=new(paasmoutput,init);
  142. codesegment:=new(paasmoutput,init);
  143. bsssegment:=new(paasmoutput,init);
  144. debuglist:=new(paasmoutput,init);
  145. externals:=new(paasmoutput,init);
  146. internals:=new(paasmoutput,init);
  147. consts:=new(paasmoutput,init);
  148. rttilist:=new(paasmoutput,init);
  149. importssection:=nil;
  150. exportssection:=nil;
  151. resourcesection:=nil;
  152. end;
  153. procedure codegen_donemodule;
  154. begin
  155. dispose(exprasmlist,done);
  156. dispose(codesegment,done);
  157. dispose(bsssegment,done);
  158. dispose(datasegment,done);
  159. dispose(debuglist,done);
  160. dispose(externals,done);
  161. dispose(consts,done);
  162. dispose(rttilist,done);
  163. if assigned(importssection) then
  164. dispose(importssection,done);
  165. if assigned(exportssection) then
  166. dispose(exportssection,done);
  167. if assigned(resourcesection) then
  168. dispose(resourcesection,done);
  169. end;
  170. {*****************************************************************************
  171. Case Helpers
  172. *****************************************************************************}
  173. function case_count_labels(root : pcaserecord) : longint;
  174. var
  175. _l : longint;
  176. procedure count(p : pcaserecord);
  177. begin
  178. inc(_l);
  179. if assigned(p^.less) then
  180. count(p^.less);
  181. if assigned(p^.greater) then
  182. count(p^.greater);
  183. end;
  184. begin
  185. _l:=0;
  186. count(root);
  187. case_count_labels:=_l;
  188. end;
  189. function case_get_max(root : pcaserecord) : longint;
  190. var
  191. hp : pcaserecord;
  192. begin
  193. hp:=root;
  194. while assigned(hp^.greater) do
  195. hp:=hp^.greater;
  196. case_get_max:=hp^._high;
  197. end;
  198. function case_get_min(root : pcaserecord) : longint;
  199. var
  200. hp : pcaserecord;
  201. begin
  202. hp:=root;
  203. while assigned(hp^.less) do
  204. hp:=hp^.less;
  205. case_get_min:=hp^._low;
  206. end;
  207. {*****************************************************************************
  208. String Helpers
  209. *****************************************************************************}
  210. procedure generate_ascii(const hs : string);
  211. begin
  212. datasegment^.concat(new(pai_string,init(hs)))
  213. end;
  214. procedure generate_ascii_insert(const hs : string);
  215. begin
  216. datasegment^.insert(new(pai_string,init(hs)));
  217. end;
  218. function strnew(p : pchar;length : longint) : pchar;
  219. var
  220. pc : pchar;
  221. begin
  222. getmem(pc,length);
  223. move(p^,pc^,length);
  224. strnew:=pc;
  225. end;
  226. { concates the ASCII string from pchar to the const segment }
  227. procedure generate_pascii(hs : pchar;length : longint);
  228. var
  229. real_end,current_begin,current_end : pchar;
  230. c :char;
  231. begin
  232. if assigned(hs) then
  233. begin
  234. current_begin:=hs;
  235. real_end:=strend(hs);
  236. c:=hs[0];
  237. while length>32 do
  238. begin
  239. { restore the char displaced }
  240. current_begin[0]:=c;
  241. current_end:=current_begin+32;
  242. { store the char for next loop }
  243. c:=current_end[0];
  244. current_end[0]:=#0;
  245. datasegment^.concat(new(pai_string,init_length_pchar(strnew(current_begin,32),32)));
  246. length:=length-32;
  247. end;
  248. datasegment^.concat(new(pai_string,init_length_pchar(strnew(current_begin,length),length)));
  249. end;
  250. end;
  251. { inserts the ASCII string from pchar to the const segment }
  252. procedure generate_pascii_insert(hs : pchar;length : longint);
  253. var
  254. real_end,current_begin,current_end : pchar;
  255. c :char;
  256. begin
  257. if assigned(hs) then
  258. begin
  259. current_begin:=hs;
  260. real_end:=strend(hs);
  261. c:=hs[0];
  262. length:=longint(real_end)-longint(hs);
  263. while length>32 do
  264. begin
  265. { restore the char displaced }
  266. current_begin[0]:=c;
  267. current_end:=current_begin+32;
  268. { store the char for next loop }
  269. c:=current_end[0];
  270. current_end[0]:=#0;
  271. datasegment^.insert(new(pai_string,init_length_pchar(strnew(current_begin,32),32)));
  272. length:=length-32;
  273. end;
  274. datasegment^.insert(new(pai_string,init_length_pchar(strnew(current_begin,length),length)));
  275. end;
  276. end;
  277. {*****************************************************************************
  278. Const Helpers
  279. *****************************************************************************}
  280. const
  281. consttypestr : array[tconsttype] of string[6]=
  282. ('ord','string','real','bool','int','char','set');
  283. function constlabel2str(p:plabel;ctype:tconsttype):string;
  284. begin
  285. if smartlink or (current_module^.output_format in [of_nasm,of_obj]) then
  286. constlabel2str:='_$'+current_module^.unitname^+'$'+consttypestr[ctype]+'_const_'+tostr(p^.nb)
  287. else
  288. constlabel2str:=lab2str(p);
  289. end;
  290. procedure concat_constlabel(p:plabel;ctype:tconsttype);
  291. var
  292. s : string;
  293. begin
  294. if smartlink or (current_module^.output_format in [of_nasm,of_obj]) then
  295. begin
  296. s:='_$'+current_module^.unitname^+'$'+consttypestr[ctype]+'_const_'+tostr(p^.nb);
  297. if smartlink then
  298. begin
  299. consts^.concat(new(pai_cut,init));
  300. consts^.concat(new(pai_symbol,init_global(s)))
  301. end
  302. else
  303. consts^.concat(new(pai_symbol,init_global(s)));
  304. end
  305. else
  306. consts^.concat(new(pai_label,init(p)));
  307. end;
  308. end.
  309. {
  310. $Log$
  311. Revision 1.4 1998-05-07 00:17:01 peter
  312. * smartlinking for sets
  313. + consts labels are now concated/generated in hcodegen
  314. * moved some cpu code to cga and some none cpu depended code from cga
  315. to tree and hcodegen and cleanup of hcodegen
  316. * assembling .. output reduced for smartlinking ;)
  317. Revision 1.3 1998/05/06 08:38:40 pierre
  318. * better position info with UseTokenInfo
  319. UseTokenInfo greatly simplified
  320. + added check for changed tree after first time firstpass
  321. (if we could remove all the cases were it happen
  322. we could skip all firstpass if firstpasscount > 1)
  323. Only with ExtDebug
  324. Revision 1.2 1998/04/29 10:33:53 pierre
  325. + added some code for ansistring (not complete nor working yet)
  326. * corrected operator overloading
  327. * corrected nasm output
  328. + started inline procedures
  329. + added starstarn : use ** for exponentiation (^ gave problems)
  330. + started UseTokenInfo cond to get accurate positions
  331. }