ncgld.pas 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate assembler for nodes that handle loads and assignments which
  5. are the same for all (most) processors
  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 ncgld;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. node,nld;
  24. type
  25. tcgloadnode = class(tloadnode)
  26. procedure pass_2;override;
  27. end;
  28. tcgassignmentnode = class(tassignmentnode)
  29. procedure pass_2;override;
  30. end;
  31. tcgarrayconstructornode = class(tarrayconstructornode)
  32. procedure pass_2;override;
  33. end;
  34. implementation
  35. uses
  36. systems,
  37. verbose,globtype,globals,
  38. symconst,symtype,symdef,symsym,symtable,defutil,paramgr,
  39. ncnv,ncon,nmem,nbas,
  40. aasmbase,aasmtai,aasmcpu,regvars,
  41. cginfo,cgbase,pass_2,
  42. cpubase,cpuinfo,
  43. tgobj,ncgutil,cgobj,rgobj;
  44. {*****************************************************************************
  45. SecondLoad
  46. *****************************************************************************}
  47. procedure tcgloadnode.pass_2;
  48. var
  49. r,hregister : tregister;
  50. supreg:Tsuperregister;
  51. symtabletype : tsymtabletype;
  52. href : treference;
  53. newsize : tcgsize;
  54. dorelocatelab,
  55. norelocatelab : tasmlabel;
  56. paraloc1 : tparalocation;
  57. begin
  58. { we don't know the size of all arrays }
  59. newsize:=def_cgsize(resulttype.def);
  60. location_reset(location,LOC_REFERENCE,newsize);
  61. case symtableentry.typ of
  62. absolutesym :
  63. begin
  64. { this is only for toasm and toaddr }
  65. if (tabsolutesym(symtableentry).abstyp=toaddr) then
  66. begin
  67. {$ifdef i386}
  68. if tabsolutesym(symtableentry).absseg then
  69. location.reference.segment:=NR_FS;
  70. {$endif i386}
  71. location.reference.offset:=tabsolutesym(symtableentry).address;
  72. end
  73. else
  74. location.reference.symbol:=objectlibrary.newasmsymboldata(tabsolutesym(symtableentry).mangledname);
  75. end;
  76. constsym:
  77. begin
  78. if tconstsym(symtableentry).consttyp=constresourcestring then
  79. begin
  80. location_reset(location,LOC_CREFERENCE,OS_ADDR);
  81. location.reference.symbol:=objectlibrary.newasmsymboldata(tconstsym(symtableentry).owner.name^+'_RESOURCESTRINGLIST');
  82. location.reference.offset:=tconstsym(symtableentry).resstrindex*16+8;
  83. end
  84. else
  85. internalerror(22798);
  86. end;
  87. varsym :
  88. begin
  89. if (tvarsym(symtableentry).varspez=vs_const) then
  90. location_reset(location,LOC_CREFERENCE,newsize);
  91. symtabletype:=symtable.symtabletype;
  92. hregister:=NR_NO;
  93. { C variable }
  94. if (vo_is_C_var in tvarsym(symtableentry).varoptions) then
  95. begin
  96. location.reference.symbol:=objectlibrary.newasmsymboldata(tvarsym(symtableentry).mangledname);
  97. end
  98. { DLL variable }
  99. else if (vo_is_dll_var in tvarsym(symtableentry).varoptions) then
  100. begin
  101. hregister:=rg.getaddressregister(exprasmlist);
  102. location.reference.symbol:=objectlibrary.newasmsymboldata(tvarsym(symtableentry).mangledname);
  103. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,location.reference,hregister);
  104. reference_reset_base(location.reference,hregister,0);
  105. end
  106. { external variable }
  107. else if (vo_is_external in tvarsym(symtableentry).varoptions) then
  108. begin
  109. location.reference.symbol:=objectlibrary.newasmsymboldata(tvarsym(symtableentry).mangledname);
  110. end
  111. { thread variable }
  112. else if (vo_is_thread_var in tvarsym(symtableentry).varoptions) then
  113. begin
  114. objectlibrary.getlabel(dorelocatelab);
  115. objectlibrary.getlabel(norelocatelab);
  116. { make sure hregister can't allocate the register necessary for the parameter }
  117. paraloc1:=paramanager.getintparaloc(pocall_default,1);
  118. paramanager.allocparaloc(exprasmlist,paraloc1);
  119. { we've to allocate the register before we save the used registers }
  120. hregister:=rg.getaddressregister(exprasmlist);
  121. reference_reset_symbol(href,objectlibrary.newasmsymboldata('FPC_THREADVAR_RELOCATE'),0);
  122. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,hregister);
  123. cg.a_cmp_const_reg_label(exprasmlist,OS_ADDR,OC_NE,0,hregister,dorelocatelab);
  124. { no relocation needed, load the address of the variable only, the
  125. layout of a threadvar is (4 bytes pointer):
  126. 0 - Threadvar index
  127. 4 - Threadvar value in single threading }
  128. reference_reset_symbol(href,objectlibrary.newasmsymboldata(tvarsym(symtableentry).mangledname),POINTER_SIZE);
  129. cg.a_loadaddr_ref_reg(exprasmlist,href,hregister);
  130. cg.a_jmp_always(exprasmlist,norelocatelab);
  131. cg.a_label(exprasmlist,dorelocatelab);
  132. { don't save the allocated register else the result will be destroyed later }
  133. reference_reset_symbol(href,objectlibrary.newasmsymboldata(tvarsym(symtableentry).mangledname),0);
  134. cg.a_param_ref(exprasmlist,OS_ADDR,href,paraloc1);
  135. { the called procedure isn't allowed to change }
  136. { any register except EAX }
  137. cg.a_call_reg(exprasmlist,hregister);
  138. paramanager.freeparaloc(exprasmlist,paraloc1);
  139. r:=rg.getexplicitregisterint(exprasmlist,NR_FUNCTION_RESULT_REG);
  140. rg.ungetregisterint(exprasmlist,r);
  141. cg.a_load_reg_reg(exprasmlist,OS_INT,OS_ADDR,r,hregister);
  142. cg.a_label(exprasmlist,norelocatelab);
  143. location.reference.base:=hregister;
  144. end
  145. { normal variable }
  146. else
  147. begin
  148. { in case it is a register variable: }
  149. if tvarsym(symtableentry).reg<>NR_NO then
  150. begin
  151. case getregtype(tvarsym(symtableentry).reg) of
  152. R_FPUREGISTER :
  153. begin
  154. location_reset(location,LOC_CFPUREGISTER,def_cgsize(resulttype.def));
  155. location.register:=tvarsym(symtableentry).reg;
  156. end;
  157. R_INTREGISTER :
  158. begin
  159. supreg:=getsupreg(Tvarsym(symtableentry).reg);
  160. if (supreg in general_superregisters) and
  161. not (supreg in rg.regvar_loaded_int) then
  162. load_regvar(exprasmlist,tvarsym(symtableentry));
  163. location_reset(location,LOC_CREGISTER,def_cgsize(resulttype.def));
  164. location.register:=tvarsym(symtableentry).reg;
  165. exclude(rg.unusedregsint,supreg);
  166. hregister := location.register;
  167. end;
  168. else
  169. internalerror(200301172);
  170. end;
  171. end
  172. else
  173. begin
  174. case symtabletype of
  175. localsymtable,
  176. parasymtable,
  177. inlinelocalsymtable,
  178. inlineparasymtable :
  179. begin
  180. location.reference.base:=current_procinfo.framepointer;
  181. location.reference.offset:=tvarsym(symtableentry).adjusted_address;
  182. if (current_procinfo.procdef.parast.symtablelevel>symtable.symtablelevel) then
  183. begin
  184. hregister:=rg.getaddressregister(exprasmlist);
  185. cg.g_load_parent_framepointer(exprasmlist,symtable,hregister);
  186. location.reference.base:=hregister;
  187. end;
  188. end;
  189. globalsymtable,
  190. staticsymtable :
  191. begin
  192. location.reference.symbol:=objectlibrary.newasmsymboldata(tvarsym(symtableentry).mangledname);
  193. end;
  194. stt_exceptsymtable:
  195. begin
  196. location.reference.base:=current_procinfo.framepointer;
  197. location.reference.offset:=tvarsym(symtableentry).address;
  198. end;
  199. else
  200. internalerror(200305102);
  201. end;
  202. end;
  203. end;
  204. { handle call by reference variables, ignore the reference
  205. when we need to load the self pointer for objects }
  206. if (symtabletype in [parasymtable,inlineparasymtable]) and
  207. not(nf_load_self_pointer in flags) and
  208. (
  209. (tvarsym(symtableentry).varspez in [vs_var,vs_out]) or
  210. paramanager.push_addr_param(tvarsym(symtableentry).vartype.def,tprocdef(symtable.defowner).proccalloption)
  211. ) then
  212. begin
  213. if hregister=NR_NO then
  214. hregister:=rg.getaddressregister(exprasmlist);
  215. { we need to load only an address }
  216. location.size:=OS_ADDR;
  217. cg.a_load_loc_reg(exprasmlist,location.size,location,hregister);
  218. if tvarsym(symtableentry).varspez=vs_const then
  219. location_reset(location,LOC_CREFERENCE,newsize)
  220. else
  221. location_reset(location,LOC_REFERENCE,newsize);
  222. location.reference.base:=hregister;
  223. end;
  224. end;
  225. procsym:
  226. begin
  227. if assigned(left) then
  228. begin
  229. {
  230. THIS IS A TERRIBLE HACK!!!!!! WHICH WILL NOT WORK
  231. ON 64-BIT SYSTEMS: SINCE PROCSYM FOR METHODS
  232. CONSISTS OF TWO OS_ADDR, so you cannot set it
  233. to OS_64 - how to solve?? Carl
  234. }
  235. if (sizeof(aword) = 4) then
  236. location_reset(location,LOC_CREFERENCE,OS_64)
  237. else
  238. internalerror(20020520);
  239. tg.GetTemp(exprasmlist,2*POINTER_SIZE,tt_normal,location.reference);
  240. secondpass(left);
  241. { load class instance address }
  242. case left.location.loc of
  243. LOC_CREGISTER,
  244. LOC_REGISTER:
  245. begin
  246. { this is not possible for objects }
  247. if is_object(left.resulttype.def) then
  248. internalerror(200304234);
  249. hregister:=left.location.register;
  250. end;
  251. LOC_CREFERENCE,
  252. LOC_REFERENCE:
  253. begin
  254. hregister:=rg.getaddressregister(exprasmlist);
  255. if is_class_or_interface(left.resulttype.def) then
  256. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,left.location.reference,hregister)
  257. else
  258. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,hregister);
  259. location_release(exprasmlist,left.location);
  260. location_freetemp(exprasmlist,left.location);
  261. end;
  262. else
  263. internalerror(26019);
  264. end;
  265. { store the class instance address }
  266. href:=location.reference;
  267. inc(href.offset,POINTER_SIZE);
  268. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,href);
  269. { virtual method ? }
  270. if (po_virtualmethod in procdef.procoptions) then
  271. begin
  272. { load vmt pointer }
  273. reference_reset_base(href,hregister,0);
  274. reference_release(exprasmlist,href);
  275. hregister:=rg.getaddressregister(exprasmlist);
  276. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,hregister);
  277. reference_reset_base(href,hregister,
  278. procdef._class.vmtmethodoffset(procdef.extnumber));
  279. reference_release(exprasmlist,href);
  280. { load method address }
  281. hregister:=rg.getaddressregister(exprasmlist);
  282. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,hregister);
  283. { ... and store it }
  284. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,location.reference);
  285. rg.ungetaddressregister(exprasmlist,hregister);
  286. end
  287. else
  288. begin
  289. { we don't use the hregister }
  290. rg.ungetregisterint(exprasmlist,hregister);
  291. { load address of the function }
  292. reference_reset_symbol(href,objectlibrary.newasmsymbol(procdef.mangledname),0);
  293. hregister:=rg.getaddressregister(exprasmlist);
  294. cg.a_loadaddr_ref_reg(exprasmlist,href,hregister);
  295. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,location.reference);
  296. rg.ungetregisterint(exprasmlist,hregister);
  297. end;
  298. end
  299. else
  300. begin
  301. {!!!!! Be aware, work on virtual methods too }
  302. location.reference.symbol:=objectlibrary.newasmsymbol(procdef.mangledname);
  303. end;
  304. end;
  305. typedconstsym :
  306. begin
  307. location.reference.symbol:=objectlibrary.newasmsymboldata(ttypedconstsym(symtableentry).mangledname);
  308. end;
  309. else internalerror(4);
  310. end;
  311. end;
  312. {*****************************************************************************
  313. SecondAssignment
  314. *****************************************************************************}
  315. procedure tcgassignmentnode.pass_2;
  316. var
  317. otlabel,hlabel,oflabel : tasmlabel;
  318. fputyp : tfloattype;
  319. href : treference;
  320. old_allow_multi_pass2,
  321. releaseright : boolean;
  322. cgsize : tcgsize;
  323. r:Tregister;
  324. begin
  325. location_reset(location,LOC_VOID,OS_NO);
  326. otlabel:=truelabel;
  327. oflabel:=falselabel;
  328. objectlibrary.getlabel(truelabel);
  329. objectlibrary.getlabel(falselabel);
  330. {
  331. in most cases we can process first the right node which contains
  332. the most complex code. But not when the result is in the flags, then
  333. loading the left node afterwards can destroy the flags.
  334. when the right node returns as LOC_JUMP then we will generate
  335. the following code:
  336. rightnode
  337. true:
  338. leftnode
  339. assign 1
  340. false:
  341. leftnode
  342. assign 0
  343. }
  344. { Try to determine which side to calculate first, }
  345. if (right.expectloc<>LOC_FLAGS) and
  346. ((right.expectloc=LOC_JUMP) or
  347. (right.nodetype=calln) or
  348. (right.registers32>=left.registers32)) then
  349. begin
  350. secondpass(right);
  351. { increment source reference counter, this is
  352. useless for string constants}
  353. if (right.resulttype.def.needs_inittable) and
  354. (right.nodetype<>stringconstn) then
  355. cg.g_incrrefcount(exprasmlist,right.resulttype.def,right.location.reference,false);
  356. if codegenerror then
  357. exit;
  358. { We skip the generation of the left node when it's a jump, see
  359. explanation above }
  360. if (right.location.loc<>LOC_JUMP) and
  361. not(nf_concat_string in flags) then
  362. begin
  363. { left can't be never a 64 bit LOC_REGISTER, so the 3. arg }
  364. { can be false }
  365. secondpass(left);
  366. { decrement destination reference counter }
  367. if (left.resulttype.def.needs_inittable) then
  368. cg.g_decrrefcount(exprasmlist,left.resulttype.def,left.location.reference,false);
  369. if codegenerror then
  370. exit;
  371. end;
  372. end
  373. else
  374. begin
  375. { calculate left sides }
  376. { don't do it yet if it's a crgister (JM) }
  377. if not(nf_concat_string in flags) then
  378. begin
  379. secondpass(left);
  380. { decrement destination reference counter }
  381. if (left.resulttype.def.needs_inittable) then
  382. cg.g_decrrefcount(exprasmlist,left.resulttype.def,left.location.reference,false);
  383. if codegenerror then
  384. exit;
  385. end;
  386. { left can't be never a 64 bit LOC_REGISTER, so the 3. arg }
  387. { can be false }
  388. secondpass(right);
  389. { increment source reference counter, this is
  390. useless for string constants}
  391. if (right.resulttype.def.needs_inittable) and
  392. (right.nodetype<>stringconstn) then
  393. cg.g_incrrefcount(exprasmlist,right.resulttype.def,right.location.reference,false);
  394. if codegenerror then
  395. exit;
  396. end;
  397. releaseright:=true;
  398. { optimize temp to temp copies }
  399. if (left.nodetype = temprefn) and
  400. { we may store certain temps in registers in the future, then this }
  401. { optimization will have to be adapted }
  402. (left.location.loc = LOC_REFERENCE) and
  403. (right.location.loc = LOC_REFERENCE) and
  404. tg.istemp(right.location.reference) and
  405. (tg.sizeoftemp(exprasmlist,right.location.reference) = tg.sizeoftemp(exprasmlist,left.location.reference)) then
  406. begin
  407. { in theory, we should also make sure the left temp type is }
  408. { already more or less of the same kind (ie. we must not }
  409. { assign an ansistring to a normaltemp). In practice, the }
  410. { assignment node will have already taken care of this for us }
  411. ttemprefnode(left).changelocation(right.location.reference);
  412. end
  413. { shortstring assignments are handled separately }
  414. else if is_shortstring(left.resulttype.def) then
  415. begin
  416. {
  417. we can get here only in the following situations
  418. for the right node:
  419. - empty constant string
  420. - char
  421. }
  422. { empty constant string }
  423. if (right.nodetype=stringconstn) and
  424. (tstringconstnode(right).len=0) then
  425. begin
  426. cg.a_load_const_ref(exprasmlist,OS_8,0,left.location.reference);
  427. end
  428. { char loading }
  429. else if is_char(right.resulttype.def) then
  430. begin
  431. if right.nodetype=ordconstn then
  432. begin
  433. if (target_info.endian = endian_little) then
  434. cg.a_load_const_ref(exprasmlist,OS_16,(tordconstnode(right).value shl 8) or 1,
  435. left.location.reference)
  436. else
  437. cg.a_load_const_ref(exprasmlist,OS_16,tordconstnode(right).value or (1 shl 8),
  438. left.location.reference);
  439. end
  440. else
  441. begin
  442. href:=left.location.reference;
  443. cg.a_load_const_ref(exprasmlist,OS_8,1,href);
  444. inc(href.offset,1);
  445. case right.location.loc of
  446. LOC_REGISTER,
  447. LOC_CREGISTER :
  448. begin
  449. r:=rg.makeregsize(right.location.register,OS_8);
  450. cg.a_load_reg_ref(exprasmlist,OS_8,OS_8,r,href);
  451. end;
  452. LOC_REFERENCE,
  453. LOC_CREFERENCE :
  454. cg.a_load_ref_ref(exprasmlist,OS_8,OS_8,right.location.reference,href);
  455. else
  456. internalerror(200205111);
  457. end;
  458. end;
  459. end
  460. else
  461. internalerror(200204249);
  462. end
  463. else
  464. begin
  465. case right.location.loc of
  466. LOC_CONSTANT :
  467. begin
  468. if right.location.size in [OS_64,OS_S64] then
  469. cg64.a_load64_const_loc(exprasmlist,
  470. right.location.valueqword,left.location)
  471. else
  472. cg.a_load_const_loc(exprasmlist,right.location.value,left.location);
  473. end;
  474. LOC_REFERENCE,
  475. LOC_CREFERENCE :
  476. begin
  477. case left.location.loc of
  478. LOC_CREGISTER :
  479. begin
  480. cgsize:=def_cgsize(left.resulttype.def);
  481. if cgsize in [OS_64,OS_S64] then
  482. cg64.a_load64_ref_reg(exprasmlist,
  483. right.location.reference,left.location.register64,false)
  484. else
  485. cg.a_load_ref_reg(exprasmlist,cgsize,cgsize,
  486. right.location.reference,left.location.register);
  487. location_release(exprasmlist,right.location);
  488. end;
  489. LOC_CFPUREGISTER :
  490. begin
  491. cg.a_loadfpu_ref_reg(exprasmlist,
  492. def_cgsize(right.resulttype.def),
  493. right.location.reference,
  494. left.location.register);
  495. end;
  496. LOC_REFERENCE,
  497. LOC_CREFERENCE :
  498. begin
  499. cg.g_concatcopy(exprasmlist,right.location.reference,
  500. left.location.reference,left.resulttype.def.size,true,false);
  501. { right.location is already released by concatcopy }
  502. releaseright:=false;
  503. end;
  504. else
  505. internalerror(200203284);
  506. end;
  507. end;
  508. {$ifdef SUPPORT_MMX}
  509. LOC_CMMXREGISTER,
  510. LOC_MMXREGISTER:
  511. begin
  512. if left.location.loc=LOC_CMMXREGISTER then
  513. cg.a_loadmm_reg_reg(exprasmlist,right.location.register,left.location.register)
  514. else
  515. cg.a_loadmm_reg_ref(exprasmlist,right.location.register,left.location.reference);
  516. end;
  517. {$endif SUPPORT_MMX}
  518. LOC_REGISTER,
  519. LOC_CREGISTER :
  520. begin
  521. cgsize:=def_cgsize(left.resulttype.def);
  522. if cgsize in [OS_64,OS_S64] then
  523. cg64.a_load64_reg_loc(exprasmlist,
  524. right.location.register64,left.location)
  525. else
  526. cg.a_load_reg_loc(exprasmlist,right.location.size,right.location.register,left.location);
  527. end;
  528. LOC_FPUREGISTER,LOC_CFPUREGISTER :
  529. begin
  530. if (left.resulttype.def.deftype=floatdef) then
  531. fputyp:=tfloatdef(left.resulttype.def).typ
  532. else
  533. if (right.resulttype.def.deftype=floatdef) then
  534. fputyp:=tfloatdef(right.resulttype.def).typ
  535. else
  536. if (right.nodetype=typeconvn) and
  537. (ttypeconvnode(right).left.resulttype.def.deftype=floatdef) then
  538. fputyp:=tfloatdef(ttypeconvnode(right).left.resulttype.def).typ
  539. else
  540. fputyp:=s32real;
  541. cg.a_loadfpu_reg_loc(exprasmlist,
  542. tfloat2tcgsize[fputyp],
  543. right.location.register,left.location);
  544. end;
  545. LOC_JUMP :
  546. begin
  547. cgsize:=def_cgsize(left.resulttype.def);
  548. objectlibrary.getlabel(hlabel);
  549. { generate the leftnode for the true case, and
  550. release the location }
  551. cg.a_label(exprasmlist,truelabel);
  552. secondpass(left);
  553. if codegenerror then
  554. exit;
  555. cg.a_load_const_loc(exprasmlist,1,left.location);
  556. location_release(exprasmlist,left.location);
  557. cg.a_jmp_always(exprasmlist,hlabel);
  558. { generate the leftnode for the false case }
  559. cg.a_label(exprasmlist,falselabel);
  560. old_allow_multi_pass2:=allow_multi_pass2;
  561. allow_multi_pass2:=true;
  562. secondpass(left);
  563. allow_multi_pass2:=old_allow_multi_pass2;
  564. if codegenerror then
  565. exit;
  566. cg.a_load_const_loc(exprasmlist,0,left.location);
  567. cg.a_label(exprasmlist,hlabel);
  568. end;
  569. {$ifdef cpuflags}
  570. LOC_FLAGS :
  571. begin
  572. {This can be a wordbool or longbool too, no?}
  573. if left.location.loc=LOC_CREGISTER then
  574. cg.g_flags2reg(exprasmlist,def_cgsize(left.resulttype.def),right.location.resflags,left.location.register)
  575. else
  576. begin
  577. if not(left.location.loc = LOC_REFERENCE) then
  578. internalerror(200203273);
  579. cg.g_flags2ref(exprasmlist,def_cgsize(left.resulttype.def),right.location.resflags,left.location.reference);
  580. end;
  581. end;
  582. {$endif cpuflags}
  583. end;
  584. end;
  585. if releaseright then
  586. location_release(exprasmlist,right.location);
  587. location_release(exprasmlist,left.location);
  588. truelabel:=otlabel;
  589. falselabel:=oflabel;
  590. end;
  591. {*****************************************************************************
  592. SecondArrayConstruct
  593. *****************************************************************************}
  594. const
  595. vtInteger = 0;
  596. vtBoolean = 1;
  597. vtChar = 2;
  598. vtExtended = 3;
  599. vtString = 4;
  600. vtPointer = 5;
  601. vtPChar = 6;
  602. vtObject = 7;
  603. vtClass = 8;
  604. vtWideChar = 9;
  605. vtPWideChar = 10;
  606. vtAnsiString = 11;
  607. vtCurrency = 12;
  608. vtVariant = 13;
  609. vtInterface = 14;
  610. vtWideString = 15;
  611. vtInt64 = 16;
  612. vtQWord = 17;
  613. procedure tcgarrayconstructornode.pass_2;
  614. var
  615. hp : tarrayconstructornode;
  616. href : treference;
  617. lt : tdef;
  618. vaddr : boolean;
  619. vtype : longint;
  620. freetemp,
  621. dovariant : boolean;
  622. elesize : longint;
  623. tmpreg : tregister;
  624. paraloc : tparalocation;
  625. begin
  626. dovariant:=(nf_forcevaria in flags) or tarraydef(resulttype.def).isvariant;
  627. if dovariant then
  628. elesize:=8
  629. else
  630. elesize:=tarraydef(resulttype.def).elesize;
  631. if nf_cargs in flags then
  632. begin
  633. location_reset(location,LOC_VOID,OS_NO);
  634. { Retrieve parameter location for push }
  635. paraloc:=paramanager.getintparaloc(pocall_cdecl,1);
  636. end
  637. else
  638. begin
  639. location_reset(location,LOC_CREFERENCE,OS_NO);
  640. fillchar(paraloc,sizeof(paraloc),0);
  641. { Allocate always a temp, also if no elements are required, to
  642. be sure that location is valid (PFV) }
  643. if tarraydef(resulttype.def).highrange=-1 then
  644. tg.GetTemp(exprasmlist,elesize,tt_normal,location.reference)
  645. else
  646. tg.GetTemp(exprasmlist,(tarraydef(resulttype.def).highrange+1)*elesize,tt_normal,location.reference);
  647. href:=location.reference;
  648. end;
  649. { Process nodes in array constructor }
  650. hp:=self;
  651. while assigned(hp) do
  652. begin
  653. if assigned(hp.left) then
  654. begin
  655. freetemp:=true;
  656. secondpass(hp.left);
  657. if codegenerror then
  658. exit;
  659. { Move flags and jump in register }
  660. if hp.left.location.loc in [LOC_FLAGS,LOC_JUMP] then
  661. location_force_reg(exprasmlist,hp.left.location,def_cgsize(hp.left.resulttype.def),false);
  662. if dovariant then
  663. begin
  664. { find the correct vtype value }
  665. vtype:=$ff;
  666. vaddr:=false;
  667. lt:=hp.left.resulttype.def;
  668. case lt.deftype of
  669. enumdef,
  670. orddef :
  671. begin
  672. if is_64bit(lt) then
  673. begin
  674. case torddef(lt).typ of
  675. s64bit:
  676. vtype:=vtInt64;
  677. u64bit:
  678. vtype:=vtQWord;
  679. end;
  680. if not(nf_cargs in flags) then
  681. begin
  682. freetemp:=false;
  683. vaddr:=true;
  684. end;
  685. end
  686. else if (lt.deftype=enumdef) or
  687. is_integer(lt) then
  688. vtype:=vtInteger
  689. else
  690. if is_boolean(lt) then
  691. vtype:=vtBoolean
  692. else
  693. if (lt.deftype=orddef) then
  694. begin
  695. case torddef(lt).typ of
  696. uchar:
  697. vtype:=vtChar;
  698. uwidechar:
  699. vtype:=vtWideChar;
  700. end;
  701. end;
  702. end;
  703. floatdef :
  704. begin
  705. vtype:=vtExtended;
  706. if not(nf_cargs in flags) then
  707. begin
  708. freetemp:=false;
  709. vaddr:=true;
  710. end;
  711. end;
  712. procvardef,
  713. pointerdef :
  714. begin
  715. if is_pchar(lt) then
  716. vtype:=vtPChar
  717. else
  718. vtype:=vtPointer;
  719. end;
  720. variantdef :
  721. begin
  722. vtype:=vtVariant;
  723. vaddr:=true;
  724. freetemp:=false;
  725. end;
  726. classrefdef :
  727. vtype:=vtClass;
  728. objectdef :
  729. vtype:=vtObject;
  730. stringdef :
  731. begin
  732. if is_shortstring(lt) then
  733. begin
  734. vtype:=vtString;
  735. vaddr:=true;
  736. freetemp:=false;
  737. end
  738. else
  739. if is_ansistring(lt) then
  740. begin
  741. vtype:=vtAnsiString;
  742. freetemp:=false;
  743. end
  744. else
  745. if is_widestring(lt) then
  746. begin
  747. vtype:=vtWideString;
  748. freetemp:=false;
  749. end;
  750. end;
  751. end;
  752. if vtype=$ff then
  753. internalerror(14357);
  754. { write C style pushes or an pascal array }
  755. if nf_cargs in flags then
  756. begin
  757. if vaddr then
  758. begin
  759. location_force_mem(exprasmlist,hp.left.location);
  760. cg.a_paramaddr_ref(exprasmlist,hp.left.location.reference,paraloc);
  761. location_release(exprasmlist,hp.left.location);
  762. if freetemp then
  763. location_freetemp(exprasmlist,hp.left.location);
  764. inc(pushedparasize,pointer_size);
  765. end
  766. else
  767. if vtype in [vtInt64,vtQword,vtExtended] then
  768. push_value_para(exprasmlist,hp.left,pocall_cdecl,0,4,paraloc)
  769. else
  770. begin
  771. cg.a_param_loc(exprasmlist,hp.left.location,paraloc);
  772. inc(pushedparasize,pointer_size);
  773. end;
  774. end
  775. else
  776. begin
  777. { write changing field update href to the next element }
  778. inc(href.offset,4);
  779. if vaddr then
  780. begin
  781. location_force_mem(exprasmlist,hp.left.location);
  782. tmpreg:=rg.getaddressregister(exprasmlist);
  783. cg.a_loadaddr_ref_reg(exprasmlist,hp.left.location.reference,tmpreg);
  784. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,tmpreg,href);
  785. rg.ungetregisterint(exprasmlist,tmpreg);
  786. location_release(exprasmlist,hp.left.location);
  787. if freetemp then
  788. location_freetemp(exprasmlist,hp.left.location);
  789. end
  790. else
  791. begin
  792. location_release(exprasmlist,hp.left.location);
  793. cg.a_load_loc_ref(exprasmlist,OS_ADDR,hp.left.location,href);
  794. end;
  795. { update href to the vtype field and write it }
  796. dec(href.offset,4);
  797. cg.a_load_const_ref(exprasmlist, OS_INT,vtype,href);
  798. { goto next array element }
  799. inc(href.offset,8);
  800. end;
  801. end
  802. else
  803. { normal array constructor of the same type }
  804. begin
  805. if is_ansistring(left.resulttype.def) or
  806. is_widestring(left.resulttype.def) or
  807. (left.resulttype.def.deftype=variantdef) then
  808. freetemp:=false;
  809. location_release(exprasmlist,hp.left.location);
  810. case hp.left.location.loc of
  811. LOC_FPUREGISTER,
  812. LOC_CFPUREGISTER :
  813. begin
  814. location_release(exprasmlist,hp.left.location);
  815. cg.a_loadfpu_reg_ref(exprasmlist,hp.left.location.size,hp.left.location.register,href);
  816. end;
  817. LOC_REFERENCE,
  818. LOC_CREFERENCE :
  819. begin
  820. cg.g_concatcopy(exprasmlist,hp.left.location.reference,href,elesize,freetemp,false);
  821. end;
  822. else
  823. begin
  824. if hp.left.location.size in [OS_64,OS_S64] then
  825. cg64.a_load64_loc_ref(exprasmlist,hp.left.location,href)
  826. else
  827. cg.a_load_loc_ref(exprasmlist,hp.left.location.size,hp.left.location,href);
  828. end;
  829. end;
  830. inc(href.offset,elesize);
  831. end;
  832. end;
  833. { load next entry }
  834. hp:=tarrayconstructornode(hp.right);
  835. end;
  836. end;
  837. begin
  838. cloadnode:=tcgloadnode;
  839. cassignmentnode:=tcgassignmentnode;
  840. carrayconstructornode:=tcgarrayconstructornode;
  841. end.
  842. {
  843. $Log$
  844. Revision 1.80 2003-09-10 08:31:47 marco
  845. * Patch from Peter for paraloc
  846. Revision 1.79 2003/09/03 15:55:00 peter
  847. * NEWRA branch merged
  848. Revision 1.78 2003/09/03 11:18:37 florian
  849. * fixed arm concatcopy
  850. + arm support in the common compiler sources added
  851. * moved some generic cg code around
  852. + tfputype added
  853. * ...
  854. Revision 1.77.2.2 2003/08/31 15:46:26 peter
  855. * more updates for tregister
  856. Revision 1.77.2.1 2003/08/29 17:28:59 peter
  857. * next batch of updates
  858. Revision 1.77 2003/08/20 20:13:08 daniel
  859. * Fixed the fixed trouble
  860. Revision 1.76 2003/08/20 20:11:24 daniel
  861. * Fixed some R_NO trouble
  862. Revision 1.75 2003/07/20 16:26:43 jonas
  863. * fix for threadvars with -dnewra
  864. Revision 1.74 2003/07/06 17:58:22 peter
  865. * framepointer fixes for sparc
  866. * parent framepointer code more generic
  867. Revision 1.73 2003/07/06 15:25:54 jonas
  868. * newra fix for threadvars
  869. Revision 1.72 2003/06/15 15:13:12 jonas
  870. * fixed register allocation for threadvar loads with newra
  871. Revision 1.71 2003/06/13 21:19:30 peter
  872. * current_procdef removed, use current_procinfo.procdef instead
  873. Revision 1.70 2003/06/12 16:43:07 peter
  874. * newra compiles for sparc
  875. Revision 1.69 2003/06/09 16:41:52 jonas
  876. * fixed regvar optimization for call_by_reference parameters (no need
  877. to load address in another register)
  878. Revision 1.68 2003/06/08 18:27:15 jonas
  879. + ability to change the location of a ttempref node with changelocation()
  880. method. Useful to use instead of copying the contents from one temp to
  881. another
  882. + some shortstring optimizations in tassignmentnode that avoid some
  883. copying (required some shortstring optimizations to be moved from
  884. resulttype to firstpass, because they work on callnodes and string
  885. addnodes are only changed to callnodes in the firstpass)
  886. * allow setting/changing the funcretnode of callnodes after the
  887. resulttypepass has been done, funcretnode is now a property
  888. (all of the above should have a quite big effect on callparatemp)
  889. Revision 1.67 2003/06/07 18:57:04 jonas
  890. + added freeintparaloc
  891. * ppc get/freeintparaloc now check whether the parameter regs are
  892. properly allocated/deallocated (and get an extra list para)
  893. * ppc a_call_* now internalerrors if pi_do_call is not yet set
  894. * fixed lot of missing pi_do_call's
  895. Revision 1.66 2003/06/03 21:11:09 peter
  896. * cg.a_load_* get a from and to size specifier
  897. * makeregsize only accepts newregister
  898. * i386 uses generic tcgnotnode,tcgunaryminus
  899. Revision 1.65 2003/06/03 13:01:59 daniel
  900. * Register allocator finished
  901. Revision 1.64 2003/05/30 23:57:08 peter
  902. * more sparc cleanup
  903. * accumulator removed, splitted in function_return_reg (called) and
  904. function_result_reg (caller)
  905. Revision 1.63 2003/05/30 23:54:08 jonas
  906. * forgot to commit, a_load_loc_reg change
  907. Revision 1.62 2003/05/26 19:38:28 peter
  908. * generic fpc_shorstr_concat
  909. + fpc_shortstr_append_shortstr optimization
  910. Revision 1.61 2003/05/24 11:47:27 jonas
  911. * fixed framepointer storage: it's now always stored at r1+12, which is
  912. a place in the link area reserved for compiler use.
  913. Revision 1.60 2003/05/23 14:27:35 peter
  914. * remove some unit dependencies
  915. * current_procinfo changes to store more info
  916. Revision 1.59 2003/05/15 18:58:53 peter
  917. * removed selfpointer_offset, vmtpointer_offset
  918. * tvarsym.adjusted_address
  919. * address in localsymtable is now in the real direction
  920. * removed some obsolete globals
  921. Revision 1.58 2003/05/12 17:22:00 jonas
  922. * fixed (last?) remaining -tvarsym(X).address to
  923. tg.direction*tvarsym(X).address...
  924. Revision 1.57 2003/05/11 21:37:03 peter
  925. * moved implicit exception frame from ncgutil to psub
  926. * constructor/destructor helpers moved from cobj/ncgutil to psub
  927. Revision 1.56 2003/05/11 14:45:12 peter
  928. * tloadnode does not support objectsymtable,withsymtable anymore
  929. * withnode cleanup
  930. * direct with rewritten to use temprefnode
  931. Revision 1.55 2003/04/29 07:29:14 michael
  932. + Patch from peter to fix wrong pushing of ansistring function results in open array
  933. Revision 1.54 2003/04/27 11:21:33 peter
  934. * aktprocdef renamed to current_procinfo.procdef
  935. * procinfo renamed to current_procinfo
  936. * procinfo will now be stored in current_module so it can be
  937. cleaned up properly
  938. * gen_main_procsym changed to create_main_proc and release_main_proc
  939. to also generate a tprocinfo structure
  940. * fixed unit implicit initfinal
  941. Revision 1.53 2003/04/27 07:29:50 peter
  942. * current_procinfo.procdef cleanup, current_procdef is now always nil when parsing
  943. a new procdef declaration
  944. * aktprocsym removed
  945. * lexlevel removed, use symtable.symtablelevel instead
  946. * implicit init/final code uses the normal genentry/genexit
  947. * funcret state checking updated for new funcret handling
  948. Revision 1.52 2003/04/25 20:59:33 peter
  949. * removed funcretn,funcretsym, function result is now in varsym
  950. and aliases for result and function name are added using absolutesym
  951. * vs_hidden parameter for funcret passed in parameter
  952. * vs_hidden fixes
  953. * writenode changed to printnode and released from extdebug
  954. * -vp option added to generate a tree.log with the nodetree
  955. * nicer printnode for statements, callnode
  956. Revision 1.51 2003/04/23 20:16:04 peter
  957. + added currency support based on int64
  958. + is_64bit for use in cg units instead of is_64bitint
  959. * removed cgmessage from n386add, replace with internalerrors
  960. Revision 1.50 2003/04/23 10:12:14 peter
  961. * allow multi pass2 changed to global boolean instead of node flag
  962. Revision 1.49 2003/04/22 23:50:22 peter
  963. * firstpass uses expectloc
  964. * checks if there are differences between the expectloc and
  965. location.loc from secondpass in EXTDEBUG
  966. Revision 1.48 2003/04/22 10:09:35 daniel
  967. + Implemented the actual register allocator
  968. + Scratch registers unavailable when new register allocator used
  969. + maybe_save/maybe_restore unavailable when new register allocator used
  970. Revision 1.47 2003/04/06 21:11:23 olle
  971. * changed newasmsymbol to newasmsymboldata for data symbols
  972. Revision 1.46 2003/03/28 19:16:56 peter
  973. * generic constructor working for i386
  974. * remove fixed self register
  975. * esi added as address register for i386
  976. Revision 1.45 2003/02/19 22:00:14 daniel
  977. * Code generator converted to new register notation
  978. - Horribily outdated todo.txt removed
  979. Revision 1.44 2003/01/08 18:43:56 daniel
  980. * Tregister changed into a record
  981. Revision 1.43 2003/01/05 22:44:14 peter
  982. * remove a lot of code to support typen in loadn-procsym
  983. Revision 1.42 2002/12/20 18:13:46 peter
  984. * fixes for fpu values in arrayconstructor
  985. Revision 1.41 2002/11/27 20:04:39 peter
  986. * cdecl array of const fixes
  987. Revision 1.40 2002/11/25 17:43:18 peter
  988. * splitted defbase in defutil,symutil,defcmp
  989. * merged isconvertable and is_equal into compare_defs(_ext)
  990. * made operator search faster by walking the list only once
  991. Revision 1.39 2002/11/22 16:22:45 jonas
  992. * fixed error in my previous commit (the size of the location of the
  993. funcretnode must be based on the current resulttype of the node and not
  994. the resulttype defined by the function; these can be different in case
  995. of "absolute" declarations)
  996. Revision 1.38 2002/11/18 17:31:54 peter
  997. * pass proccalloption to ret_in_xxx and push_xxx functions
  998. Revision 1.37 2002/11/15 21:16:39 jonas
  999. * proper fix for tw2110, also fixes tb0416 (funcretnode of parent
  1000. function was handled wrong inside nested functions/procedures)
  1001. Revision 1.36 2002/11/15 01:58:51 peter
  1002. * merged changes from 1.0.7 up to 04-11
  1003. - -V option for generating bug report tracing
  1004. - more tracing for option parsing
  1005. - errors for cdecl and high()
  1006. - win32 import stabs
  1007. - win32 records<=8 are returned in eax:edx (turned off by default)
  1008. - heaptrc update
  1009. - more info for temp management in .s file with EXTDEBUG
  1010. Revision 1.35 2002/10/14 19:44:13 peter
  1011. * (hacked) new threadvar relocate code
  1012. Revision 1.34 2002/10/13 11:22:06 florian
  1013. * fixed threadvars
  1014. Revision 1.33 2002/10/03 21:32:02 carl
  1015. * bugfix for 2110 (without -Or), wrong checking was done in returntype
  1016. Revision 1.32 2002/09/30 07:00:46 florian
  1017. * fixes to common code to get the alpha compiler compiled applied
  1018. Revision 1.31 2002/09/26 15:02:05 florian
  1019. + support of passing variants to "array of const"
  1020. Revision 1.30 2002/09/17 18:54:02 jonas
  1021. * a_load_reg_reg() now has two size parameters: source and dest. This
  1022. allows some optimizations on architectures that don't encode the
  1023. register size in the register name.
  1024. Revision 1.29 2002/09/07 15:25:03 peter
  1025. * old logs removed and tabs fixed
  1026. Revision 1.28 2002/09/01 19:26:32 peter
  1027. * fixed register variable loading from parasymtable, the call by
  1028. reference code was moved wrong
  1029. Revision 1.27 2002/09/01 12:15:40 peter
  1030. * fixed loading of procvar of object when the object is initialized
  1031. with 0
  1032. Revision 1.26 2002/08/25 19:25:18 peter
  1033. * sym.insert_in_data removed
  1034. * symtable.insertvardata/insertconstdata added
  1035. * removed insert_in_data call from symtable.insert, it needs to be
  1036. called separatly. This allows to deref the address calculation
  1037. * procedures now calculate the parast addresses after the procedure
  1038. directives are parsed. This fixes the cdecl parast problem
  1039. * push_addr_param has an extra argument that specifies if cdecl is used
  1040. or not
  1041. Revision 1.25 2002/08/23 16:14:48 peter
  1042. * tempgen cleanup
  1043. * tt_noreuse temp type added that will be used in genentrycode
  1044. Revision 1.24 2002/08/17 09:23:35 florian
  1045. * first part of procinfo rewrite
  1046. Revision 1.23 2002/08/14 18:13:28 jonas
  1047. * adapted previous fix to Peter's asmsymbol patch
  1048. Revision 1.22 2002/08/14 18:00:42 jonas
  1049. * fixed tb0403
  1050. Revision 1.21 2002/08/13 21:40:56 florian
  1051. * more fixes for ppc calling conventions
  1052. Revision 1.20 2002/08/11 14:32:26 peter
  1053. * renamed current_library to objectlibrary
  1054. Revision 1.19 2002/08/11 13:24:12 peter
  1055. * saving of asmsymbols in ppu supported
  1056. * asmsymbollist global is removed and moved into a new class
  1057. tasmlibrarydata that will hold the info of a .a file which
  1058. corresponds with a single module. Added librarydata to tmodule
  1059. to keep the library info stored for the module. In the future the
  1060. objectfiles will also be stored to the tasmlibrarydata class
  1061. * all getlabel/newasmsymbol and friends are moved to the new class
  1062. Revision 1.18 2002/08/06 20:55:21 florian
  1063. * first part of ppc calling conventions fix
  1064. Revision 1.17 2002/07/28 09:25:37 carl
  1065. + correct size of parameter (64-bit portability)
  1066. Revision 1.16 2002/07/27 19:53:51 jonas
  1067. + generic implementation of tcg.g_flags2ref()
  1068. * tcg.flags2xxx() now also needs a size parameter
  1069. Revision 1.15 2002/07/20 11:57:54 florian
  1070. * types.pas renamed to defbase.pas because D6 contains a types
  1071. unit so this would conflicts if D6 programms are compiled
  1072. + Willamette/SSE2 instructions to assembler added
  1073. Revision 1.14 2002/07/16 09:17:44 florian
  1074. * threadvar relocation result wasn't handled properly, it could cause
  1075. a crash
  1076. Revision 1.13 2002/07/11 14:41:28 florian
  1077. * start of the new generic parameter handling
  1078. Revision 1.12 2002/07/07 09:52:32 florian
  1079. * powerpc target fixed, very simple units can be compiled
  1080. * some basic stuff for better callparanode handling, far from being finished
  1081. Revision 1.11 2002/07/01 18:46:23 peter
  1082. * internal linker
  1083. * reorganized aasm layer
  1084. Revision 1.10 2002/07/01 16:23:53 peter
  1085. * cg64 patch
  1086. * basics for currency
  1087. * asnode updates for class and interface (not finished)
  1088. Revision 1.9 2002/05/20 13:30:40 carl
  1089. * bugfix of hdisponen (base must be set, not index)
  1090. * more portability fixes
  1091. }