hcodegen.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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. { the definition of the proc itself }
  45. def : pdef;
  46. { frame pointer offset }
  47. framepointer_offset : longint;
  48. { self pointer offset }
  49. ESI_offset : longint;
  50. { result value offset }
  51. retoffset : longint;
  52. { firsttemp position }
  53. firsttemp : longint;
  54. funcret_is_valid : boolean;
  55. { parameter offset }
  56. call_offset : longint;
  57. { some collected informations about the procedure }
  58. { see pi_xxxx above }
  59. flags : longint;
  60. { register used as frame pointer }
  61. framepointer : tregister;
  62. { true, if the procedure is exported by an unit }
  63. globalsymbol : boolean;
  64. { true, if the procedure should be exported (only OS/2) }
  65. exported : boolean;
  66. { code for the current procedure }
  67. aktproccode,aktentrycode,
  68. aktexitcode,aktlocaldata : paasmoutput;
  69. { local data is used for smartlink }
  70. end;
  71. var
  72. { info about the current sub routine }
  73. procinfo : tprocinfo;
  74. { labels for BREAK and CONTINUE }
  75. aktbreaklabel,aktcontinuelabel : plabel;
  76. { label when the result is true or false }
  77. truelabel,falselabel : plabel;
  78. { label to leave the sub routine }
  79. aktexitlabel : plabel;
  80. { also an exit label, only used we need to clear only the stack }
  81. aktexit2label : plabel;
  82. { only used in constructor for fail or if getmem fails }
  83. quickexitlabel : plabel;
  84. { Boolean, wenn eine loadn kein Assembler erzeugt hat }
  85. simple_loadn : boolean;
  86. { tries to hold the amount of times which the current tree is processed }
  87. t_times : longint;
  88. { true, if an error while code generation occurs }
  89. codegenerror : boolean;
  90. { initialize respectively terminates the code generator }
  91. { for a new module or procedure }
  92. procedure codegen_doneprocedure;
  93. procedure codegen_donemodule;
  94. procedure codegen_newmodule;
  95. procedure codegen_newprocedure;
  96. { counts the labels }
  97. function case_count_labels(root : pcaserecord) : longint;
  98. { searches the highest label }
  99. function case_get_max(root : pcaserecord) : longint;
  100. { searches the lowest label }
  101. function case_get_min(root : pcaserecord) : longint;
  102. { concates/inserts the ASCII string to the data segment }
  103. procedure generate_ascii(const hs : string);
  104. procedure generate_ascii_insert(const hs : string);
  105. { concates/inserts the ASCII string from pchar to the data segment }
  106. { WARNING : if hs has no #0 and strlen(hs)=length }
  107. { the terminal zero is not written }
  108. procedure generate_pascii(hs : pchar;length : longint);
  109. procedure generate_pascii_insert(hs : pchar;length : longint);
  110. { convert/concats a label for constants in the consts section }
  111. function constlabel2str(l : plabel;ctype:tconsttype):string;
  112. function constlabelnb2str(pnb : longint;ctype:tconsttype):string;
  113. procedure concat_constlabel(p:plabel;ctype:tconsttype);
  114. implementation
  115. uses
  116. systems,cobjects,globals,files,strings;
  117. {*****************************************************************************
  118. initialize/terminate the codegen for procedure and modules
  119. *****************************************************************************}
  120. procedure codegen_newprocedure;
  121. begin
  122. aktbreaklabel:=nil;
  123. aktcontinuelabel:=nil;
  124. { aktexitlabel:=0; is store in oldaktexitlabel
  125. so it must not be reset to zero before this storage !}
  126. { the type of this lists isn't important }
  127. { because the code of this lists is }
  128. { copied to the code segment }
  129. procinfo.aktentrycode:=new(paasmoutput,init);
  130. procinfo.aktexitcode:=new(paasmoutput,init);
  131. procinfo.aktproccode:=new(paasmoutput,init);
  132. procinfo.aktlocaldata:=new(paasmoutput,init);
  133. end;
  134. procedure codegen_doneprocedure;
  135. begin
  136. dispose(procinfo.aktentrycode,done);
  137. dispose(procinfo.aktexitcode,done);
  138. dispose(procinfo.aktproccode,done);
  139. dispose(procinfo.aktlocaldata,done);
  140. end;
  141. procedure codegen_newmodule;
  142. begin
  143. exprasmlist:=new(paasmoutput,init);
  144. datasegment:=new(paasmoutput,init);
  145. codesegment:=new(paasmoutput,init);
  146. bsssegment:=new(paasmoutput,init);
  147. debuglist:=new(paasmoutput,init);
  148. externals:=new(paasmoutput,init);
  149. internals:=new(paasmoutput,init);
  150. consts:=new(paasmoutput,init);
  151. rttilist:=new(paasmoutput,init);
  152. importssection:=nil;
  153. exportssection:=nil;
  154. resourcesection:=nil;
  155. end;
  156. procedure codegen_donemodule;
  157. begin
  158. dispose(exprasmlist,done);
  159. dispose(codesegment,done);
  160. dispose(bsssegment,done);
  161. dispose(datasegment,done);
  162. dispose(debuglist,done);
  163. dispose(externals,done);
  164. dispose(consts,done);
  165. dispose(rttilist,done);
  166. if assigned(importssection) then
  167. dispose(importssection,done);
  168. if assigned(exportssection) then
  169. dispose(exportssection,done);
  170. if assigned(resourcesection) then
  171. dispose(resourcesection,done);
  172. end;
  173. {*****************************************************************************
  174. Case Helpers
  175. *****************************************************************************}
  176. function case_count_labels(root : pcaserecord) : longint;
  177. var
  178. _l : longint;
  179. procedure count(p : pcaserecord);
  180. begin
  181. inc(_l);
  182. if assigned(p^.less) then
  183. count(p^.less);
  184. if assigned(p^.greater) then
  185. count(p^.greater);
  186. end;
  187. begin
  188. _l:=0;
  189. count(root);
  190. case_count_labels:=_l;
  191. end;
  192. function case_get_max(root : pcaserecord) : longint;
  193. var
  194. hp : pcaserecord;
  195. begin
  196. hp:=root;
  197. while assigned(hp^.greater) do
  198. hp:=hp^.greater;
  199. case_get_max:=hp^._high;
  200. end;
  201. function case_get_min(root : pcaserecord) : longint;
  202. var
  203. hp : pcaserecord;
  204. begin
  205. hp:=root;
  206. while assigned(hp^.less) do
  207. hp:=hp^.less;
  208. case_get_min:=hp^._low;
  209. end;
  210. {*****************************************************************************
  211. String Helpers
  212. *****************************************************************************}
  213. procedure generate_ascii(const hs : string);
  214. begin
  215. datasegment^.concat(new(pai_string,init(hs)))
  216. end;
  217. procedure generate_ascii_insert(const hs : string);
  218. begin
  219. datasegment^.insert(new(pai_string,init(hs)));
  220. end;
  221. function strnew(p : pchar;length : longint) : pchar;
  222. var
  223. pc : pchar;
  224. begin
  225. getmem(pc,length);
  226. move(p^,pc^,length);
  227. strnew:=pc;
  228. end;
  229. { concates the ASCII string from pchar to the const segment }
  230. procedure generate_pascii(hs : pchar;length : longint);
  231. var
  232. real_end,current_begin,current_end : pchar;
  233. c :char;
  234. begin
  235. if assigned(hs) then
  236. begin
  237. current_begin:=hs;
  238. real_end:=strend(hs);
  239. c:=hs[0];
  240. while length>32 do
  241. begin
  242. { restore the char displaced }
  243. current_begin[0]:=c;
  244. current_end:=current_begin+32;
  245. { store the char for next loop }
  246. c:=current_end[0];
  247. current_end[0]:=#0;
  248. datasegment^.concat(new(pai_string,init_length_pchar(strnew(current_begin,32),32)));
  249. length:=length-32;
  250. end;
  251. datasegment^.concat(new(pai_string,init_length_pchar(strnew(current_begin,length),length)));
  252. end;
  253. end;
  254. { inserts the ASCII string from pchar to the const segment }
  255. procedure generate_pascii_insert(hs : pchar;length : longint);
  256. var
  257. real_end,current_begin,current_end : pchar;
  258. c :char;
  259. begin
  260. if assigned(hs) then
  261. begin
  262. current_begin:=hs;
  263. real_end:=strend(hs);
  264. c:=hs[0];
  265. length:=longint(real_end)-longint(hs);
  266. while length>32 do
  267. begin
  268. { restore the char displaced }
  269. current_begin[0]:=c;
  270. current_end:=current_begin+32;
  271. { store the char for next loop }
  272. c:=current_end[0];
  273. current_end[0]:=#0;
  274. datasegment^.insert(new(pai_string,init_length_pchar(strnew(current_begin,32),32)));
  275. length:=length-32;
  276. end;
  277. datasegment^.insert(new(pai_string,init_length_pchar(strnew(current_begin,length),length)));
  278. end;
  279. end;
  280. {*****************************************************************************
  281. Const Helpers
  282. *****************************************************************************}
  283. const
  284. consttypestr : array[tconsttype] of string[6]=
  285. ('ord','string','real','bool','int','char','set');
  286. { Peter this gives problems for my inlines !! }
  287. { we must use the number directly !!! (PM) }
  288. function constlabel2str(l : plabel;ctype:tconsttype):string;
  289. begin
  290. if smartlink or (current_module^.output_format in [of_nasm,of_obj]) then
  291. constlabel2str:='_$'+current_module^.unitname^+'$'+consttypestr[ctype]+'_const_'+tostr(l^.nb)
  292. else
  293. constlabel2str:=lab2str(l);
  294. end;
  295. function constlabelnb2str(pnb : longint;ctype:tconsttype):string;
  296. begin
  297. if smartlink or (current_module^.output_format in [of_nasm,of_obj]) then
  298. constlabelnb2str:='_$'+current_module^.unitname^+'$'+consttypestr[ctype]+'_const_'+tostr(pnb)
  299. else
  300. constlabelnb2str:=target_asm.labelprefix+tostr(pnb);
  301. end;
  302. procedure concat_constlabel(p:plabel;ctype:tconsttype);
  303. var
  304. s : string;
  305. begin
  306. if smartlink or (current_module^.output_format in [of_nasm,of_obj]) then
  307. begin
  308. s:='_$'+current_module^.unitname^+'$'+consttypestr[ctype]+'_const_'+tostr(p^.nb);
  309. if smartlink then
  310. begin
  311. consts^.concat(new(pai_cut,init));
  312. consts^.concat(new(pai_symbol,init_global(s)))
  313. end
  314. else
  315. consts^.concat(new(pai_symbol,init_global(s)));
  316. end
  317. else
  318. consts^.concat(new(pai_label,init(p)));
  319. end;
  320. end.
  321. {
  322. $Log$
  323. Revision 1.5 1998-05-20 09:42:34 pierre
  324. + UseTokenInfo now default
  325. * unit in interface uses and implementation uses gives error now
  326. * only one error for unknown symbol (uses lastsymknown boolean)
  327. the problem came from the label code !
  328. + first inlined procedures and function work
  329. (warning there might be allowed cases were the result is still wrong !!)
  330. * UseBrower updated gives a global list of all position of all used symbols
  331. with switch -gb
  332. Revision 1.4 1998/05/07 00:17:01 peter
  333. * smartlinking for sets
  334. + consts labels are now concated/generated in hcodegen
  335. * moved some cpu code to cga and some none cpu depended code from cga
  336. to tree and hcodegen and cleanup of hcodegen
  337. * assembling .. output reduced for smartlinking ;)
  338. Revision 1.3 1998/05/06 08:38:40 pierre
  339. * better position info with UseTokenInfo
  340. UseTokenInfo greatly simplified
  341. + added check for changed tree after first time firstpass
  342. (if we could remove all the cases were it happen
  343. we could skip all firstpass if firstpasscount > 1)
  344. Only with ExtDebug
  345. Revision 1.2 1998/04/29 10:33:53 pierre
  346. + added some code for ansistring (not complete nor working yet)
  347. * corrected operator overloading
  348. * corrected nasm output
  349. + started inline procedures
  350. + added starstarn : use ** for exponentiation (^ gave problems)
  351. + started UseTokenInfo cond to get accurate positions
  352. }