genstmt.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248
  1. /*
  2. * GTools C compiler
  3. * =================
  4. * source file :
  5. * statement generator
  6. *
  7. * Copyright 2001-2004 Paul Froissart.
  8. * Credits to Christoph van Wuellen and Matthew Brandt.
  9. * All commercial rights reserved.
  10. *
  11. * This compiler may be redistributed as long there is no
  12. * commercial interest. The compiler must not be redistributed
  13. * without its full sources. This notice must stay intact.
  14. */
  15. #include "define.h"
  16. _FILE(__FILE__)
  17. #include "c.h"
  18. #include "expr.h"
  19. #include "gen.h"
  20. #include "cglbdec.h"
  21. #ifndef PC
  22. #define checkstack() while (0)
  23. #endif
  24. int nextlabel CGLOB;
  25. /*int uses_structassign CGLOB;*/
  26. TYP *ret_type CGLOB;
  27. XLST_TYPE lc_auto CGLOB;
  28. XLST_TYPE max_scratch CGLOB;
  29. #ifdef MC680X0
  30. unsigned int save_mask CGLOB;
  31. #endif
  32. xstatic unsigned int breaklab CGLOB;
  33. xstatic unsigned int contlab CGLOB;
  34. xstatic unsigned int retlab CGLOB;
  35. void genstmt(struct snode *stmt);
  36. struct amode *mk_reg(int r) {
  37. /*
  38. * make an address reference to a register.
  39. */
  40. struct amode *ap;
  41. ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+MK_REG);
  42. #ifdef MC680X0
  43. if (r < AREGBASE) {
  44. ap->mode = am_dreg;
  45. ap->preg = r;
  46. } else {
  47. ap->mode = am_areg;
  48. ap->preg = r - AREGBASE;
  49. }
  50. #endif
  51. #ifdef INTEL_386
  52. ap->mode = am_reg;
  53. ap->preg = r;
  54. #endif
  55. return ap;
  56. }
  57. #ifdef MC680X0
  58. struct amode *mk_rmask(unsigned int mask) {
  59. /*
  60. * generate the mask address structure.
  61. */
  62. struct amode *ap;
  63. ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+MK_MASK);
  64. ap->mode = am_mask1;
  65. ap->offset = mk_icon((long) mask);
  66. return ap;
  67. }
  68. struct amode *mk_smask(unsigned int mask) {
  69. /*
  70. * generate the mask address structure.
  71. */
  72. struct amode *ap;
  73. ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+MK_MASK);
  74. ap->mode = am_mask2;
  75. ap->offset = mk_icon((long) mask);
  76. return ap;
  77. }
  78. #endif
  79. struct amode *mk_strlab(char *s) {
  80. /*
  81. * generate a direct reference to a string label.
  82. */
  83. struct amode *ap;
  84. ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+MK_STRLAB);
  85. ap->mode = am_direct;
  86. ap->offset = mk_node(en_nacon, NIL_ENODE, NIL_ENODE);
  87. ap->offset->v.ensp = s;
  88. #ifdef AS
  89. ap->offset->v.enlab = label(s);
  90. #endif
  91. return ap;
  92. }
  93. static void genwhile(struct snode *stmt) {
  94. /*
  95. * generate code to evaluate a while statement.
  96. */
  97. unsigned int lab1, lab2;
  98. initstack(); /* initialize temp registers */
  99. lab1 = contlab; /* save old continue label */
  100. lab2 = breaklab; /* save old break label */
  101. contlab = nxtlabel(); /* new continue label */
  102. #ifdef ICODE
  103. if (icode_option)
  104. fprintf(icode, "\tL%u:\n", contlab);
  105. #endif
  106. g_label(contlab);
  107. if (stmt->s1 != 0) { /* has block */
  108. breaklab = nxtlabel();
  109. initstack();
  110. #ifdef ICODE
  111. if (icode_option) {
  112. fprintf(icode, "*falsejp L%u\n", breaklab);
  113. g_icode(stmt->exp);
  114. }
  115. #endif
  116. falsejp(stmt->exp, breaklab);
  117. checkstack();
  118. genstmt(stmt->s1);
  119. g_code(op_bra, 0, mk_label(contlab), NIL_AMODE);
  120. g_label(breaklab);
  121. #ifdef ICODE
  122. if (icode_option) {
  123. fprintf(icode, "\tbranch_unconditional\tL%u\n", contlab);
  124. fprintf(icode, "\tL%u:\n", breaklab);
  125. }
  126. #endif
  127. breaklab = lab2; /* restore old break label */
  128. } else { /* no loop code */
  129. initstack();
  130. #ifdef ICODE
  131. if (icode_option) {
  132. fprintf(icode, "*truejp L%u\n", contlab);
  133. g_icode(stmt->exp);
  134. }
  135. #endif
  136. truejp(stmt->exp, contlab);
  137. checkstack();
  138. }
  139. contlab = lab1; /* restore old continue label */
  140. }
  141. struct amode *g_deref();
  142. static void genloop(struct snode *stmt) {
  143. /*
  144. * generate code to evaluate a loop statement.
  145. */
  146. unsigned int lab1, lab2;
  147. struct amode *counter,*ap2;
  148. struct enode *node;
  149. initstack(); /* initialize temp registers */
  150. lab1 = contlab; /* save old continue label */
  151. lab2 = breaklab; /* save old break label */
  152. node=stmt->exp->v.p[0];
  153. counter = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+GENLOOP);
  154. switch (node->nodetype) {
  155. case en_autocon:
  156. counter->mode = am_indx;
  157. counter->preg = FRAMEPTR - AREGBASE; /* frame pointer */
  158. counter->offset = node; /* use as constant node */
  159. break;
  160. case en_tempref:
  161. if (node->v.i < AREGBASE) {
  162. counter->mode = am_dreg;
  163. counter->preg = (reg_t)node->v.i;
  164. } else {
  165. fatal("LOOP can't use aregs");
  166. /* counter->mode = am_areg;
  167. counter->preg = (reg_t)(node->v.i - AREGBASE);*/
  168. }
  169. break;
  170. case en_nacon:
  171. case en_labcon:
  172. counter->mode = am_direct;
  173. counter->offset = node;
  174. break;
  175. case en_ref:
  176. counter=g_deref(node->v.p[0],node->etype,F_MEM|F_USES,node->esize);
  177. break;
  178. default:
  179. ierr(GENLOOP,1);
  180. }
  181. // ap2 = g_expr(stmt->exp, F_ALL);
  182. ap2 = g_expr(stmt->exp->v.p[1], F_ALL | F_SRCOP);
  183. g_code(op_move, 2, ap2, counter);
  184. freeop(ap2);
  185. if (counter->mode==am_dreg && counter->preg<=MAX_DATA)
  186. ierr(GENLOOP,2);
  187. contlab = nxtlabel(); /* new continue label */
  188. #ifdef ICODE
  189. if (icode_option)
  190. fprintf(icode, "\tL%u:\n", contlab);
  191. #endif
  192. g_label(contlab);
  193. breaklab = nxtlabel();
  194. if (stmt->s1 != 0) /* has block */
  195. genstmt(stmt->s1);
  196. if (stmt->v2.e != 0) { /* has 'until' condition */
  197. #ifdef ICODE
  198. if (icode_option) {
  199. fprintf(icode, "*truejp L%u\n", breaklab);
  200. g_icode(stmt->v1.e);
  201. }
  202. #endif
  203. truejp(stmt->v2.e, breaklab);
  204. }
  205. if (counter->mode==am_dreg) g_code(op_dbra, 0, counter, mk_label(contlab));
  206. else {
  207. struct amode *ap1;
  208. ap1 = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+GENLOOP);
  209. ap1->mode = am_immed;
  210. ap1->offset = mk_icon(1L);
  211. g_code(op_subq, 2, ap1, counter);
  212. g_code(op_bhs, 0, mk_label(contlab), NIL_AMODE);
  213. }
  214. g_label(breaklab);
  215. #ifdef ICODE
  216. if (icode_option) {
  217. fprintf(icode, "\tbranch_unconditional\tL%u\n", contlab);
  218. fprintf(icode, "\tL%u:\n", breaklab);
  219. }
  220. #endif
  221. breaklab = lab2; /* restore old break label */
  222. contlab = lab1; /* restore old continue label */
  223. }
  224. #ifndef ASM
  225. static void genasm(struct snode *stmt) {
  226. g_code(_op_asm, 0, (struct amode *)stmt->v1.i, NIL_AMODE);
  227. }
  228. #else
  229. #ifdef VCG
  230. extern int vcg_lvl;
  231. extern int vcg_aborted[];
  232. #endif
  233. static void genasm(struct snode *stmt) {
  234. struct ocode *ip=(struct ocode *)stmt->v1.i;
  235. #ifdef VCG
  236. if (vcg_lvl!=VCG_MAX)
  237. vcg_aborted[vcg_lvl]++;
  238. else
  239. #endif
  240. while (ip) {
  241. add_peep(ip);
  242. ip=ip->fwd;
  243. }
  244. }
  245. #endif
  246. static void g_for(struct snode *stmt) {
  247. /*
  248. * generate code to evaluate a for loop
  249. */
  250. unsigned int old_break, old_cont, exit_label, loop_label;
  251. old_break = breaklab;
  252. old_cont = contlab;
  253. loop_label = nxtlabel();
  254. exit_label = nxtlabel();
  255. if (stmt->v2.e != 0)
  256. contlab = nxtlabel();
  257. else
  258. contlab = loop_label;
  259. #ifdef ICODE
  260. if (icode_option) {
  261. if (stmt->exp != 0)
  262. g_icode(stmt->exp);
  263. fprintf(icode, "\tL%u:\n", loop_label);
  264. }
  265. #endif
  266. initstack();
  267. if (stmt->exp != 0) {
  268. (void) g_expr(stmt->exp, F_ALL | F_SRCOP | F_NOVALUE);
  269. checkstack();
  270. }
  271. g_label(loop_label);
  272. initstack();
  273. if (stmt->v1.e != 0) {
  274. #ifdef ICODE
  275. if (icode_option) {
  276. fprintf(icode, "*falsejp L%u\n", exit_label);
  277. g_icode(stmt->v1.e);
  278. }
  279. #endif
  280. falsejp(stmt->v1.e, exit_label);
  281. checkstack();
  282. }
  283. if (stmt->s1 != 0) {
  284. breaklab = exit_label;
  285. genstmt(stmt->s1);
  286. }
  287. #ifdef ICODE
  288. if (icode_option) {
  289. if (stmt->v2.e != 0) {
  290. fprintf(icode, "\tL%u:\n", contlab);
  291. g_icode(stmt->v2.e);
  292. }
  293. fprintf(icode, "\tbranch_unconditional\tL%u\n", loop_label);
  294. }
  295. #endif
  296. initstack();
  297. if (stmt->v2.e != 0) {
  298. g_label(contlab);
  299. (void) g_expr(stmt->v2.e, F_ALL | F_SRCOP | F_NOVALUE);
  300. checkstack();
  301. }
  302. g_code(op_bra, 0, mk_label(loop_label), NIL_AMODE);
  303. breaklab = old_break;
  304. contlab = old_cont;
  305. g_label(exit_label);
  306. #ifdef ICODE
  307. if (icode_option)
  308. fprintf(icode, "\tL%u:\n", exit_label);
  309. #endif
  310. }
  311. static void genif(struct snode *stmt) {
  312. /*
  313. * generate code to evaluate an if statement.
  314. */
  315. unsigned int lab1, lab2, oldbreak;
  316. lab1 = nxtlabel(); /* else label */
  317. lab2 = nxtlabel(); /* exit label */
  318. oldbreak = breaklab; /* save break label */
  319. #ifdef ICODE
  320. if (icode_option) {
  321. fprintf(icode, "*falsejp L%u\n", lab1);
  322. g_icode(stmt->exp);
  323. }
  324. #endif
  325. initstack(); /* clear temps */
  326. falsejp(stmt->exp, lab1);
  327. checkstack();
  328. if (stmt->s1 != 0 && stmt->s1->next != 0) {
  329. if (stmt->v1.s != 0)
  330. breaklab = lab2;
  331. else
  332. breaklab = lab1;
  333. }
  334. genstmt(stmt->s1);
  335. if (stmt->v1.s != 0) { /* else part exists */
  336. g_code(op_bra, 0, mk_label(lab2), NIL_AMODE);
  337. g_label(lab1);
  338. #ifdef ICODE
  339. if (icode_option) {
  340. fprintf(icode, "\tbranch_unconditional\tL%u\n", lab2);
  341. fprintf(icode, "\tL%u:\n", lab1);
  342. }
  343. #endif
  344. if (stmt->v1.s == 0 || stmt->v1.s->next == 0)
  345. breaklab = oldbreak;
  346. else
  347. breaklab = lab2;
  348. genstmt(stmt->v1.s);
  349. g_label(lab2);
  350. #ifdef ICODE
  351. if (icode_option)
  352. fprintf(icode, "\tL%u:\n", lab2);
  353. #endif
  354. } else { /* no else code */
  355. g_label(lab1);
  356. #ifdef ICODE
  357. if (icode_option)
  358. fprintf(icode, "\tL%u:\n", lab1);
  359. #endif
  360. }
  361. breaklab = oldbreak;
  362. }
  363. static void gendo(struct snode *stmt) {
  364. /*
  365. * generate code for a do - while loop.
  366. */
  367. unsigned int oldcont, oldbreak, dolab;
  368. oldcont = contlab;
  369. oldbreak = breaklab;
  370. dolab = nxtlabel();
  371. contlab = nxtlabel();
  372. breaklab = nxtlabel();
  373. g_label(dolab);
  374. #ifdef ICODE
  375. if (icode_option)
  376. fprintf(icode, "\tL%u:\n", dolab);
  377. #endif
  378. genstmt(stmt->s1); /* generate body */
  379. g_label(contlab);
  380. #ifdef ICODE
  381. if (icode_option) {
  382. fprintf(icode, "\tL%u:\n", contlab);
  383. fprintf(icode, "*truejp L%u\n", dolab);
  384. g_icode(stmt->exp);
  385. fprintf(icode, "\tL%u:\n", breaklab);
  386. }
  387. #endif
  388. initstack();
  389. truejp(stmt->exp, dolab);
  390. checkstack();
  391. g_label(breaklab);
  392. breaklab = oldbreak;
  393. contlab = oldcont;
  394. }
  395. void call_library(char *lib_name) {
  396. /*
  397. * generate a call to a library routine.
  398. * it is assumed that lib_name won't be clobbered
  399. */
  400. struct sym *sp;
  401. sp = gsearch(lib_name, -1);
  402. if (sp == 0) {
  403. pchsearch(lib_name,PCHS_ADD);
  404. sp = gsearch(lib_name, -1);
  405. if (sp == 0) {
  406. ++global_flag;
  407. sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM);
  408. #ifdef NO_CALLOC
  409. sp->tp = 0;
  410. #endif
  411. sp->name = strsave(lib_name);
  412. sp->storage_class = sc_external;
  413. append(&sp, &gsyms);
  414. --global_flag;
  415. }
  416. }
  417. sp->used = 1;
  418. #ifdef MC680X0
  419. g_code(op_jsr, 0, mk_strlab(sp->name), NIL_AMODE);
  420. #endif
  421. #ifdef INTEL_386
  422. g_code(op_call, 0, mk_strlab(sp->name), NIL_AMODE);
  423. #endif
  424. }
  425. static void genswitch(struct snode *stmt) {
  426. /*
  427. * generate a linear search switch statement.
  428. */
  429. unsigned int curlab;
  430. unsigned int deflab;
  431. unsigned int tablab;
  432. long i;
  433. struct snode *defcase, *s;
  434. struct amode *ap, *ap1;
  435. #ifndef USE_WORDS_IN_SWITCH
  436. struct amode *ap2;
  437. #endif
  438. struct enode *ep;
  439. long size;
  440. enum(e_bt) type;
  441. long min_caselabel, max_caselabel, nxt_caselabel;
  442. int number_of_cases;
  443. defcase = 0;
  444. #ifdef ICODE
  445. if (icode_option) {
  446. fprintf(icode, "$switchexp\n");
  447. g_icode(stmt->exp);
  448. }
  449. #endif
  450. initstack();
  451. #ifdef MC680X0
  452. ap = g_expr(stmt->exp, F_DREG | F_VOL);
  453. #endif
  454. #ifdef INTEL_386
  455. ap = g_expr(stmt->exp, F_REG);
  456. #endif
  457. size = stmt->exp->esize;
  458. type = stmt->exp->etype;
  459. stmt = stmt->s1;
  460. /*
  461. * analyze the switch statement
  462. */
  463. s = stmt;
  464. if (s != 0 && s->stype == st_default) {
  465. defcase = s;
  466. s = s->s1;
  467. }
  468. /* s points to the first case label */
  469. number_of_cases = 1;
  470. if (s != 0) {
  471. max_caselabel = min_caselabel = s->v2.i;
  472. s = s->s1;
  473. while (s != 0) {
  474. if (s->stype == st_default) {
  475. defcase = s;
  476. } else {
  477. if (s->v2.i > max_caselabel)
  478. max_caselabel = s->v2.i;
  479. else if (s->v2.i < min_caselabel)
  480. min_caselabel = s->v2.i;
  481. number_of_cases++;
  482. }
  483. s = s->s1;
  484. }
  485. }
  486. if (number_of_cases > 7 &&
  487. (max_caselabel - min_caselabel) / number_of_cases <= 5) {
  488. /*
  489. * we need the case label as a 32-bit item.
  490. */
  491. #ifdef MC680X0
  492. switch (type) {
  493. case bt_char:
  494. g_code(op_ext, 2, ap, NIL_AMODE);
  495. #ifndef USE_WORDS_IN_SWITCH
  496. /*FALLTHROUGH*/
  497. case bt_short:
  498. g_code(op_ext, 4, ap, NIL_AMODE);
  499. break;
  500. case bt_uchar:
  501. g_code(op_and, 4, mk_immed(255l), ap);
  502. break;
  503. case bt_ushort:
  504. g_code(op_and, 4, mk_immed(65535l), ap);
  505. #else
  506. break;
  507. case bt_uchar:
  508. g_code(op_and, 2, mk_immed(255l), ap);
  509. break;
  510. #endif
  511. }
  512. #endif
  513. #ifdef INTEL_386
  514. switch (type) {
  515. case bt_char:
  516. g_code(op_movsbl, 0, ap, ap);
  517. break;
  518. case bt_short:
  519. g_code(op_movswl, 0, ap, ap);
  520. break;
  521. case bt_uchar:
  522. g_code(op_movzbl, 0, ap, ap);
  523. break;
  524. case bt_ushort:
  525. g_code(op_movzwl, 0, ap, ap);
  526. }
  527. #endif
  528. /*
  529. * move the interval
  530. */
  531. #ifdef MC680X0
  532. #ifndef USE_WORDS_IN_SWITCH
  533. #define switch_size 4
  534. #else
  535. #define switch_size 2
  536. #endif
  537. if (min_caselabel != 0) {
  538. g_code(op_sub, switch_size, mk_immed(min_caselabel), ap);
  539. g_code(op_cmp, switch_size, mk_immed(max_caselabel - min_caselabel), ap);
  540. } else
  541. g_code(op_cmp, (int) size,
  542. mk_immed(max_caselabel-min_caselabel), ap);
  543. #endif
  544. #ifdef INTEL_386
  545. if (min_caselabel != 0) {
  546. g_code (op_sub, 4, mk_immed(min_caselabel), ap);
  547. g_code(op_cmp, 4, mk_immed(max_caselabel-min_caselabel), ap);
  548. } else
  549. g_code(op_cmp, (int) size,
  550. mk_immed(max_caselabel-min_caselabel), ap);
  551. #endif
  552. if (defcase == 0)
  553. deflab = breaklab;
  554. else {
  555. deflab = nxtlabel();
  556. defcase->v2.i = deflab;
  557. }
  558. #ifdef MC680X0
  559. g_code(op_bhi, 0, mk_label(deflab), NIL_AMODE);
  560. #endif
  561. #ifdef INTEL_386
  562. g_code(op_ja, 0, mk_label(deflab), NIL_AMODE);
  563. #endif
  564. tablab = nxtlabel();
  565. #ifdef MC680X0
  566. #ifndef USE_WORDS_IN_SWITCH
  567. g_code(op_add, 4, ap, ap);
  568. g_code(op_add, 4, ap, ap);
  569. #else
  570. g_code(op_add, 2, ap, ap);
  571. #endif
  572. ap1 = temp_addr();
  573. g_code(op_lea, 0, mk_label(tablab), ap1);
  574. #ifndef USE_WORDS_IN_SWITCH
  575. g_code(op_add, 4, ap, ap1);
  576. #endif
  577. freeop(ap1);
  578. ap1 = copy_addr(ap1);
  579. #ifndef USE_WORDS_IN_SWITCH
  580. ap1->mode = am_ind;
  581. ap2 = temp_addr();
  582. g_code(op_move, 4, ap1, ap2);
  583. ap2 = copy_addr(ap2);
  584. ap2->mode = am_ind;
  585. g_code(op_jmp, 0, ap2, NIL_AMODE);
  586. freeop(ap2);
  587. #else
  588. ap1->mode=am_indx2;
  589. ap1->sreg=ap->preg;
  590. ap1->slen=2;
  591. ap1->offset=mk_icon(0l);
  592. g_code(op_move, 2, ap1, ap);
  593. g_code(op_jmp, 0, ap1, NIL_AMODE);
  594. #endif
  595. freeop(ap);
  596. #endif
  597. #ifdef INTEL_386
  598. g_code(op_shl, 4, mk_immed(2l), ap);
  599. ep = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
  600. ep->v.enlab = tablab;
  601. ap1 = copy_addr(ap);
  602. ap1->mode = am_indx;
  603. ap1->offset = ep;
  604. g_code(op_mov, 4, ap1, ap);
  605. ap1=copy_addr(ap);
  606. ap1->mode = am_star;
  607. /*
  608. * DO NOT USE OP_BRA here....
  609. * op_bra is reserved for jumps to internal labels.
  610. * This keeps things easy in the peephole optimizer
  611. * While producing assembler output, op_bra and op_jmp yield
  612. * the same
  613. */
  614. g_code(op_jmp, 0, ap1, NIL_AMODE);
  615. freeop(ap);
  616. #endif
  617. /*
  618. * now, ship out the switch table
  619. * we have just generated the following code (MC68000 expample)
  620. *
  621. * sub.l #min_caselabel,d0
  622. * cmp.l #max_caselabel-min_caselabel,d0
  623. * bhi deflab
  624. * add.l d0,d0
  625. * add.l d0,d0
  626. * lea table,a0
  627. * add.l d0,a0
  628. * move.l (a0),a0
  629. * jmp (a0)
  630. */
  631. /*
  632. * search the cases: look for min_caselabel. nxt_caselabel is set to
  633. * the label looked for in the next pass
  634. */
  635. #ifdef ICODE
  636. if (icode_option)
  637. fprintf(icode, "default ==> L%u\n",
  638. (unsigned int) deflab);
  639. #endif
  640. //#ifdef AS
  641. g_label(tablab);
  642. //#else
  643. // cseg();
  644. // nl();
  645. // put_align(AL_POINTER);
  646. // put_label(tablab);
  647. //#endif
  648. ep = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
  649. ep->v.enlab=deflab;
  650. {
  651. #ifdef USE_WORDS_IN_SWITCH
  652. struct enode *ep0 = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
  653. struct amode *ap0;
  654. ep0->v.enlab=tablab;
  655. ap0=mk_offset(mk_node(en_sub,ep,ep0));
  656. #endif
  657. while (min_caselabel <= max_caselabel) {
  658. nxt_caselabel = max_caselabel + 1;
  659. s = stmt;
  660. while (s != 0) {
  661. if (s->stype != st_default) {
  662. if (s->v2.i == min_caselabel) {
  663. ep = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
  664. s->v2.i = ep->v.enlab = nxtlabel();
  665. /* remove statment from the list */
  666. s->stype = st_default;
  667. #ifndef USE_WORDS_IN_SWITCH
  668. //#ifdef AS
  669. g_code(op_dc, 4, mk_offset(ep), NIL_AMODE);
  670. // this is because AS can't handle local references in 'genptr'
  671. //#else
  672. // genptr(ep);
  673. //#endif
  674. #else
  675. ep=mk_node(en_sub,ep,ep0);
  676. g_code(op_dc, 2, mk_offset(ep), NIL_AMODE);
  677. #endif
  678. #ifdef ICODE
  679. if (icode_option)
  680. fprintf(icode, "case-value %8ld ==> L%u\n",
  681. min_caselabel, (unsigned int) (s->v2.i));
  682. #endif
  683. } else if (nxt_caselabel > s->v2.i)
  684. nxt_caselabel = s->v2.i;
  685. }
  686. s = s->s1;
  687. }
  688. /* fill the holes */
  689. for (i = min_caselabel + 1; i < nxt_caselabel; i++) {
  690. #ifndef USE_WORDS_IN_SWITCH
  691. ep = mk_node(en_labcon, NIL_ENODE, NIL_ENODE);
  692. ep->v.enlab = deflab;
  693. //#ifdef AS
  694. g_code(op_dc, 4, mk_offset(ep), NIL_AMODE);
  695. // this is because AS can't handle local references in 'genptr'
  696. //#else
  697. // genptr(ep);
  698. //#endif
  699. #else
  700. g_code(op_dc, 2, ap0, NIL_AMODE);
  701. #endif
  702. #ifdef ICODE
  703. if (icode_option)
  704. fprintf(icode, "case-value %8ld ==> L%u\n",
  705. i, (unsigned int) deflab);
  706. #endif
  707. }
  708. min_caselabel = nxt_caselabel;
  709. }
  710. }
  711. nl();
  712. } else {
  713. /*
  714. * generate sequential compare instructions this is not very
  715. * intelligent, but quicker than a lookup in a (value,label) table
  716. * and has no startup time, this makes it fast if there are few
  717. * labels.
  718. */
  719. while (stmt != 0) {
  720. curlab = nxtlabel();
  721. if (stmt->stype == st_default) { /* default case ? */
  722. defcase = stmt;
  723. } else {
  724. #ifdef MC680X0
  725. g_code(op_cmp, (int) size, mk_immed((long) stmt->v2.i), ap);
  726. g_code(op_beq, 0, mk_label(curlab), NIL_AMODE);
  727. #endif
  728. #ifdef INTEL_386
  729. g_code(op_cmp, (int) size, mk_immed((long) stmt->v2.i), ap);
  730. g_code(op_je, 0, mk_label(curlab), NIL_AMODE);
  731. #endif
  732. #ifdef ICODE
  733. if (icode_option)
  734. fprintf(icode, "*ifeq\t%ld,L%u\n", stmt->v2.i, curlab);
  735. #endif
  736. }
  737. stmt->v2.i = curlab;
  738. stmt = stmt->s1;
  739. }
  740. if (defcase == 0) {
  741. g_code(op_bra, 0, mk_label(breaklab), NIL_AMODE);
  742. #ifdef ICODE
  743. if (icode_option)
  744. fprintf(icode, "\tbranch_unconditional\tL%u\n", breaklab);
  745. #endif
  746. } else {
  747. g_code(op_bra, 0, mk_label((unsigned int) defcase->v2.i),
  748. NIL_AMODE);
  749. #ifdef ICODE
  750. if (icode_option)
  751. fprintf(icode, "\tbranch_unconditional\tL%u\n",
  752. (unsigned int) defcase->v2.i);
  753. #endif
  754. }
  755. freeop(ap);
  756. }
  757. checkstack();
  758. }
  759. static void gencase(struct snode *stmt) {
  760. /*
  761. * generate the label for the case statement.
  762. */
  763. g_label((unsigned int) stmt->v2.i);
  764. #ifdef ICODE
  765. if (icode_option)
  766. fprintf(icode, "\tL%u:\n", (unsigned int) stmt->v2.i);
  767. #endif
  768. }
  769. static void genxswitch(struct snode *stmt) {
  770. /*
  771. * analyze and generate best switch statement.
  772. */
  773. int oldbreak;
  774. oldbreak = breaklab;
  775. breaklab = nxtlabel();
  776. genswitch(stmt);
  777. genstmt(stmt->v1.s);
  778. g_label(breaklab);
  779. #ifdef ICODE
  780. if (icode_option)
  781. fprintf(icode, "\tL%u:\n", breaklab);
  782. #endif
  783. breaklab = oldbreak;
  784. }
  785. static void genreturn(struct snode *stmt) {
  786. /*
  787. * generate a return statement.
  788. */
  789. struct amode *ap;
  790. struct enode *ep,*ep1;
  791. // long stack_offset;
  792. if (stmt != 0 && stmt->exp != 0) {
  793. #ifdef ICODE
  794. if (icode_option) {
  795. fprintf(icode, "$return_value\n");
  796. g_icode(stmt->exp);
  797. }
  798. #endif
  799. initstack();
  800. switch (ret_type->type) {
  801. case bt_struct:
  802. case bt_union:
  803. aggregate:
  804. /* uses_structassign = 1;*/
  805. #ifdef SHORT_STRUCT_PASSING
  806. if (ret_type->size<=4) {
  807. if (stmt->exp->nodetype!=en_ref)
  808. ierr(GENRETURN,1);
  809. ap = g_expr(stmt->exp->v.p[0], F_AREG);
  810. ap = copy_addr(ap);
  811. ap->mode = am_ind;
  812. g_code(op_move,ret_type->size,ap,mk_reg(RESULT));
  813. freeop(ap);
  814. break;
  815. }
  816. #endif
  817. /* assign structure */
  818. ep = mk_node(en_autocon, NIL_ENODE, NIL_ENODE);
  819. ep->v.i = 8;
  820. ep->esize = 4;
  821. ep->etype = bt_pointer;
  822. ep = mk_node(en_ref, ep, NIL_ENODE);
  823. ep->etype = bt_pointer;
  824. ep->esize = 4;
  825. ep1 = mk_node(en_ref, ep, NIL_ENODE);
  826. ep1->etype = ret_type->type;
  827. ep1->esize = ret_type->size;
  828. ep1 = mk_node(en_assign, ep1, stmt->exp);
  829. ep1->etype = ret_type->type;
  830. ep1->esize = ret_type->size;
  831. (void) g_expr(ep1, F_ALL | F_SRCOP | F_NOVALUE);
  832. #ifdef MC680X0
  833. /* move pointer to A0 */
  834. ap = g_expr(ep, F_ALL | F_SRCOP);
  835. g_code(op_move, 4, ap, mk_reg(PRESULT));
  836. freeop(ap);
  837. #endif
  838. #ifdef INTEL_386
  839. /* move pointer to eax */
  840. ap = g_expr(ep, F_ALL | F_SRCOP);
  841. g_code(op_mov, 4, ap, mk_reg(RESULT));
  842. freeop(ap);
  843. #endif
  844. break;
  845. case bt_float:
  846. #ifdef DOUBLE
  847. case bt_double:
  848. #endif
  849. #ifdef INTEL_386
  850. /* return floating point value on top of fpu stack */
  851. (void) g_expr(stmt->exp, F_FPSTACK);
  852. #ifdef FUNCS_USE_387
  853. if (!fpu_option)
  854. /*
  855. * .fpgetstack may pop off the top of the software stack into
  856. * the hardware stack. Thus this function can be linked with
  857. * code that expexts the result value in the hardware stack.
  858. */
  859. call_library(".fpgetstack"); // obsolete
  860. #endif
  861. /* DO NOT call freeop since this might pop the value off */
  862. break;
  863. #endif
  864. #ifdef MC68000
  865. #ifndef BCDFLT
  866. /* fallthrough, return value in RESULT register */
  867. #else
  868. goto aggregate;
  869. #endif
  870. #endif
  871. case bt_char:
  872. case bt_uchar:
  873. case bt_short:
  874. case bt_ushort:
  875. case bt_long:
  876. case bt_ulong:
  877. #ifdef MC680X0
  878. /* evaluate a parameter in D0 */
  879. ap = g_expr(stmt->exp, (F_ALL | F_SRCOP)&~F_AREG);
  880. g_code(op_move, (int) stmt->exp->esize, ap, mk_reg(RESULT));
  881. freeop(ap);
  882. #endif
  883. #ifdef INTEL_386
  884. case bt_pointer:
  885. /* evaluate a parameter in eax */
  886. ap = g_expr(stmt->exp, F_ALL);
  887. g_code(op_mov, (int) stmt->exp->esize, ap, mk_reg(RESULT));
  888. freeop(ap);
  889. #endif
  890. break;
  891. #ifdef MC680X0
  892. case bt_pointer:
  893. /* evaluate a parameter in A0 */
  894. ap = g_expr(stmt->exp, (F_ALL | F_SRCOP)&~F_DREG);
  895. g_code(op_move, (int) stmt->exp->esize, ap, mk_reg(PRESULT));
  896. freeop(ap);
  897. break;
  898. #endif
  899. case bt_void:
  900. uwarn("return <val> in function returning void");
  901. break;
  902. default:
  903. ierr(GENRETURN,1);
  904. }
  905. checkstack();
  906. }
  907. /*
  908. * The epilogue is now postponed till the end of the function body since
  909. * we have to know the final value of max_scratch
  910. * If stmt is zero, this is the implicit return statement at the end of
  911. * the function
  912. */
  913. if (stmt != 0) {
  914. if (retlab == 0)
  915. retlab = nxtlabel();
  916. g_code(op_bra, 0, mk_label(retlab), NIL_AMODE);
  917. #ifdef ICODE
  918. if (icode_option)
  919. fprintf(icode, "\tbranch_unconditional\tL%u\n", retlab);
  920. #endif
  921. } else {
  922. if (retlab != 0) {
  923. g_label(retlab);
  924. #ifdef ICODE
  925. if (icode_option)
  926. fprintf(icode, "\tL%u:\n", retlab);
  927. #endif
  928. }
  929. /*
  930. * Note that if the function has called other functions (imagine alloca!),
  931. * the only safe reference to the saved registers is via the framepointer,
  932. * not the stackpointer.
  933. */
  934. #ifdef MC680X0
  935. if (regs_used > 0) {
  936. #ifndef USE_LINK
  937. if (!uses_link)
  938. #endif
  939. g_code(op_movem, 4, pop_am, mk_smask(save_mask));
  940. #ifndef USE_LINK
  941. else {
  942. int stack_offset = lc_auto + max_scratch + 4*regs_used;
  943. #ifdef BIGSTACK
  944. if (stack_offset <= 32768l) {
  945. #endif
  946. ap=mk_reg(TRUE_FRAMEPTR);
  947. ap->mode = am_indx;
  948. ap->offset = mk_icon(-stack_offset);
  949. g_code(op_movem, 4, ap, mk_smask(save_mask));
  950. #ifdef BIGSTACK
  951. } else {
  952. ap = mk_reg(STACKPTR);
  953. g_code(op_move, 4, mk_reg(TRUE_FRAMEPTR), ap);
  954. g_code(op_sub, 4, mk_immed(stack_offset), ap);
  955. g_code(op_movem, 4, pop_am, mk_smask(save_mask));
  956. }
  957. #endif
  958. }
  959. #endif
  960. }
  961. #ifdef USE_LINK
  962. g_code(op_unlk, 0, mk_reg(FRAMEPTR), NIL_AMODE);
  963. #else
  964. if (uses_link)
  965. g_code(op_unlk, 0, mk_reg(TRUE_FRAMEPTR), NIL_AMODE);
  966. else if (lc_auto || max_scratch)
  967. g_code(op_add, 4, mk_immed(lc_auto + max_scratch), mk_reg(STACKPTR));
  968. #endif
  969. g_code(op_rts, 0, NIL_AMODE, NIL_AMODE);
  970. #endif
  971. #ifdef INTEL_386
  972. /*
  973. * Adjust stack pointer to initial value
  974. */
  975. if (regs_used > 0 && !is_leaf_function) {
  976. stack_offset = lc_auto + max_scratch + 4*regs_used;
  977. ap = mk_reg(EBP);
  978. ap->mode = am_indx;
  979. ap->offset = mk_icon(-stack_offset);
  980. g_code(op_lea, 4, ap, mk_reg(ESP));
  981. }
  982. /*
  983. * pop clobbered register variables
  984. */
  985. if (esi_used)
  986. g_code(op_pop, 4, mk_reg(ESI), NIL_AMODE);
  987. if (edi_used)
  988. g_code(op_pop, 4, mk_reg(EDI), NIL_AMODE);
  989. if (ebx_used)
  990. g_code(op_pop, 4, mk_reg(EBX), NIL_AMODE);
  991. g_code(op_leave, 0, NIL_AMODE, NIL_AMODE);
  992. g_code(op_ret, 0, NIL_AMODE, NIL_AMODE);
  993. #endif
  994. #ifdef ICODE
  995. if (icode_option)
  996. fprintf(icode, "\t$leave\n");
  997. #endif
  998. }
  999. }
  1000. struct amode *lastexpr_am;
  1001. int need_res;
  1002. void genstmt(struct snode *stmt) {
  1003. /*
  1004. * genstmt will generate a statement and follow the next pointer until the
  1005. * block is generated.
  1006. */
  1007. while (stmt != 0) {
  1008. #ifdef DB_POSSIBLE
  1009. lineid=stmt->line;
  1010. #endif
  1011. switch (stmt->stype) {
  1012. case st_label:
  1013. g_label((unsigned int) stmt->v2.i);
  1014. #ifdef ICODE
  1015. if (icode_option)
  1016. fprintf(icode, "\tL%u:\n", (unsigned int) stmt->v2.i);
  1017. #endif
  1018. genstmt(stmt->s1);
  1019. break;
  1020. case st_goto:
  1021. g_code(op_bra, 0, mk_label((unsigned int) stmt->v2.i), NIL_AMODE);
  1022. #ifdef ICODE
  1023. if (icode_option)
  1024. fprintf(icode, "\tbranch_unconditional\tL%u\n",
  1025. (unsigned int) stmt->v2.i);
  1026. #endif
  1027. break;
  1028. case st_expr: {
  1029. int flgs;
  1030. #ifdef ICODE
  1031. if (icode_option)
  1032. g_icode(stmt->exp);
  1033. #endif
  1034. initstack();
  1035. /* if ((long)stmt->exp==0x7b82cc)
  1036. bkpt();*/
  1037. lastexpr_am=g_expr(stmt->exp, flgs =
  1038. (!(stmt->next) && need_res ? F_ALL | F_SRCOP : F_ALL | F_SRCOP | F_NOVALUE));
  1039. if (flgs & F_NOVALUE) checkstack();
  1040. break;
  1041. }
  1042. case st_return:
  1043. genreturn(stmt);
  1044. break;
  1045. case st_if:
  1046. genif(stmt);
  1047. break;
  1048. case st_asm:
  1049. genasm(stmt);
  1050. break;
  1051. case st_loop:
  1052. genloop(stmt);
  1053. break;
  1054. case st_while:
  1055. genwhile(stmt);
  1056. break;
  1057. case st_do:
  1058. gendo(stmt);
  1059. break;
  1060. case st_for:
  1061. g_for(stmt);
  1062. break;
  1063. case st_continue:
  1064. g_code(op_bra, 0, mk_label(contlab), NIL_AMODE);
  1065. #ifdef ICODE
  1066. if (icode_option)
  1067. fprintf(icode, "\tbranch_unconditional\tL%u\n", contlab);
  1068. #endif
  1069. break;
  1070. case st_break:
  1071. g_code(op_bra, 0, mk_label(breaklab), NIL_AMODE);
  1072. #ifdef ICODE
  1073. if (icode_option)
  1074. fprintf(icode, "\tbranch_unconditional\tL%u\n", breaklab);
  1075. #endif
  1076. break;
  1077. case st_switch:
  1078. genxswitch(stmt);
  1079. break;
  1080. case st_compound:
  1081. genstmt(stmt->s1);
  1082. break;
  1083. case st_case:
  1084. case st_default:
  1085. gencase(stmt);
  1086. genstmt(stmt->v1.s);
  1087. break;
  1088. default:
  1089. ierr(GENSTMT,1);
  1090. break;
  1091. }
  1092. stmt = stmt->next;
  1093. }
  1094. }
  1095. extern SYM *func_sp;
  1096. extern SYM *parmsp[CONVENTION_MAX_DATA+1+CONVENTION_MAX_ADDR+1+1];
  1097. void genfuncbegin(void) {
  1098. #ifdef REGPARM
  1099. int dregs=func_sp->tp->rp_dn, aregs=func_sp->tp->rp_an;
  1100. int dreg=RESULT, areg=PRESULT;
  1101. #endif
  1102. #ifdef BIGSTACK
  1103. if (lc_auto < 32768l) {
  1104. #ifdef REGPARM
  1105. #error This codes needs a little fix if REGPARM is defined...
  1106. #endif
  1107. #endif
  1108. #ifdef USE_LINK
  1109. g_coder(op_link, 0, mk_reg(FRAMEPTR), mk_immed(-lc_auto));
  1110. #else
  1111. #ifndef REGPARM
  1112. if (uses_link)
  1113. g_coder(op_link, 0, mk_reg(TRUE_FRAMEPTR), mk_immed(-lc_auto));
  1114. else if (lc_auto) g_coder(op_sub, 4, mk_immed(lc_auto), mk_reg(STACKPTR));
  1115. #else
  1116. if (!uses_link && lc_auto!=reg_size)
  1117. g_coder(op_sub, 4, mk_immed(lc_auto-reg_size), mk_reg(STACKPTR));
  1118. #endif
  1119. #endif
  1120. #ifdef BIGSTACK
  1121. } else {
  1122. g_coder(op_sub, 4, mk_immed(lc_auto), mk_reg(STACKPTR));
  1123. #ifdef USE_LINK
  1124. if (uses_link)
  1125. g_coder(op_link, 0, mk_reg(FRAMEPTR), mk_immed(0l));
  1126. #endif
  1127. }
  1128. #endif
  1129. /* now generate pushing code for reg params */
  1130. #ifdef REGPARM
  1131. { struct amode *apl[CONVENTION_MAX_DATA+1+CONVENTION_MAX_ADDR+1];
  1132. int aps[CONVENTION_MAX_DATA+1+CONVENTION_MAX_ADDR+1],i=0;
  1133. SYM **spp=parmsp;
  1134. while (*spp) {
  1135. SYM *sp1 = *spp++;
  1136. if (dregs || aregs) {
  1137. apl[i]=mk_reg(((sp1->tp->type==bt_pointer && aregs) || !dregs)
  1138. ?(aregs--, areg++):(dregs--, dreg++));
  1139. aps[i]=sp1->tp->size;
  1140. aps[i]+=aps[i]&1;
  1141. if (uses_link) {
  1142. struct amode *ap = (struct amode *) xalloc((int) sizeof(struct amode),
  1143. AMODE+G_DEREF);
  1144. ap->mode = am_indx;
  1145. ap->preg = FRAMEPTR-AREGBASE;
  1146. ap->offset = mk_icon(sp1->value.i);
  1147. g_coder(op_move, aps[i], apl[i], ap);
  1148. }
  1149. i++;
  1150. } else break;
  1151. }
  1152. if (!uses_link) {
  1153. // i=nparms; if (i>dregs+aregs) i=dregs+aregs;
  1154. while (i--) g_coder(op_move, aps[i], apl[i], push_am);
  1155. } else g_coder(op_link, 0, mk_reg(TRUE_FRAMEPTR), mk_immed(-lc_auto));
  1156. }
  1157. #endif
  1158. }
  1159. void genfunc(struct snode *stmt) {
  1160. /*
  1161. * generate a function body.
  1162. */
  1163. #ifdef VERBOSE
  1164. time_t ltime;
  1165. #endif /* VERBOSE */
  1166. int line0 = lineid;
  1167. retlab = contlab = breaklab = 0;
  1168. max_scratch = 0;
  1169. if (lc_auto % AL_DEFAULT != 0)
  1170. lc_auto += AL_DEFAULT - (lc_auto % AL_DEFAULT);
  1171. #ifdef VERBOSE
  1172. times(&tms_buf);
  1173. ltime = tms_buf.tms_utime;
  1174. #endif /* VERBOSE */
  1175. #ifdef SHOWSTEP
  1176. printf("\ncse");
  1177. #endif
  1178. opt1(stmt);
  1179. #ifdef SHOWSTEP
  1180. printf(" ok ");
  1181. #endif
  1182. #ifdef VERBOSE
  1183. times(&tms_buf);
  1184. opt_time += tms_buf.tms_utime - ltime;
  1185. #endif /* VERBOSE */
  1186. need_res=0;
  1187. #ifdef SHOWSTEP
  1188. printf("\ngen");
  1189. #endif
  1190. genstmt(stmt);
  1191. genreturn(NIL_SNODE);
  1192. #ifdef SHOWSTEP
  1193. printf(" ok ");
  1194. #endif
  1195. /*
  1196. * It is desirable to postpone the generation of the
  1197. * stack fram until here since it it now possible for
  1198. * the code generation routines to allocate stack space
  1199. * as they want. A little hack (defining g_coder)
  1200. * allows us to put the following code to the BEGINNING
  1201. * of a function body. Note that this means that we have
  1202. * to generate all code in REVERSE order
  1203. */
  1204. lineid = line0;
  1205. lc_auto += max_scratch;
  1206. #ifdef MC680X0
  1207. genfuncbegin();
  1208. #endif
  1209. #ifdef INTEL_386
  1210. if (lc_auto != 0)
  1211. g_coder(op_sub, 4, mk_immed(lc_auto), mk_reg(STACKPTR));
  1212. g_coder(op_mov, 4, mk_reg(STACKPTR), mk_reg(FRAMEPTR));
  1213. g_coder(op_push, 4, mk_reg(FRAMEPTR), NIL_AMODE);
  1214. #endif
  1215. #ifdef ICODE
  1216. if (icode_option)
  1217. fprintf(icode, "\t$framesize was %ld\n", lc_auto);
  1218. #endif
  1219. }
  1220. // vim:ts=4:sw=4