ic.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. /* $Id$ */
  2. /*
  3. * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
  4. * See the copyright notice in the ACK home directory, in the file "Copyright".
  5. */
  6. /* I N T E R M E D I A T E C O D E
  7. *
  8. * I C . C
  9. */
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include <em_spec.h>
  13. #include <em_pseu.h>
  14. #include <em_flag.h>
  15. #include <em_mes.h>
  16. #include "../share/types.h"
  17. #include "../share/debug.h"
  18. #include "../share/def.h"
  19. #include "../share/map.h"
  20. #include "ic.h"
  21. #include "ic_lookup.h"
  22. #include "ic_aux.h"
  23. #include "ic_io.h"
  24. #include "ic_lib.h"
  25. #include "../share/alloc.h"
  26. #include "../share/global.h"
  27. #include "../share/files.h"
  28. #include "../share/put.h"
  29. #include "../share/aux.h"
  30. /* Global variables */
  31. dblock_p db;
  32. dblock_p hol0_db; /* dblock for ABS block */
  33. char* curhol; /* name of hol block in current scope */
  34. dblock_p ldblock; /* last dblock */
  35. proc_p lproc; /* last proc */
  36. short tabval; /* used by table1, table2 and table3 */
  37. offset tabval2;
  38. char string[IDL + 1];
  39. line_p firstline; /* first line of current procedure */
  40. line_p lastline; /* last line read */
  41. int labelcount; /* # labels in current procedure */
  42. short fragm_type = DUNKNOWN; /* fragm. type: DCON, DROM or DUNKNOWN */
  43. short fragm_nr = 0; /* fragment number */
  44. obj_id lastoid = 0;
  45. proc_id lastpid = 0;
  46. dblock_id lastdid = 0;
  47. lab_id lastlid = 0;
  48. offset mespar = UNKNOWN_SIZE;
  49. /* argumument of ps_par message of current procedure */
  50. extern process_lines();
  51. extern int readline();
  52. extern line_p readoperand();
  53. extern line_p inpseudo();
  54. main(argc, argv) int argc;
  55. char* argv[];
  56. {
  57. /* The input files must be legal EM Compact
  58. * Assembly Language files, as produced by the EM Peephole
  59. * Optimizer.
  60. * Their file names are passed as arguments.
  61. * The output consists of the files:
  62. * - lfile: the EM code in Intermediate Code format
  63. * - dfile: the data block table file
  64. * - pfile: the proc table file
  65. * - pdump: the names of all procedures
  66. * - ddump: the names of all data blocks
  67. */
  68. /* The input file names */
  69. const char* pdump_out = argv[1];
  70. const char* ddump_out = argv[2];
  71. /* The output file names */
  72. const char* pname_out = argv[5];
  73. const char* dname_out = argv[6];
  74. const char* lname_out = argv[7];
  75. FILE* lfile = openfile(lname_out, "w");
  76. FILE* pdump = openfile(pdump_out, "w");
  77. FILE* ddump = openfile(ddump_out, "w");
  78. FILE* dfile;
  79. FILE* pfile;
  80. hol0_db = block_of_lab((char*)0);
  81. while (next_file(argc-8, argv+8) != NULL)
  82. {
  83. /* Read all EM input files, process the code
  84. * and concatenate all output.
  85. */
  86. curhol = (char*)0;
  87. process_lines(lfile);
  88. dump_procnames(prochash, NPROCHASH, pdump);
  89. dump_dblocknames(symhash, NSYMHASH, ddump);
  90. /* Save the names of all procedures that were
  91. * first come accross in this file.
  92. */
  93. cleanprocs(prochash, NPROCHASH, PF_EXTERNAL);
  94. cleandblocks(symhash, NSYMHASH, DF_EXTERNAL);
  95. /* Make all procedure names that were internal
  96. * in this input file invisible.
  97. */
  98. }
  99. fclose(lfile);
  100. fclose(pdump);
  101. fclose(ddump);
  102. /* remove the remainder of the hashing tables */
  103. cleanprocs(prochash, NPROCHASH, 0);
  104. cleandblocks(symhash, NSYMHASH, 0);
  105. /* Now write the datablock table and the proctable */
  106. dfile = openfile(dname_out, "w");
  107. putdtable(fdblock, dfile);
  108. pfile = openfile(pname_out, "w");
  109. putptable(fproc, pfile, FALSE);
  110. exit(0);
  111. }
  112. /* Value returned by readline */
  113. #define NORMAL 0
  114. #define WITH_OPERAND 1
  115. #define EOFILE 2
  116. #define PRO_INSTR 3
  117. #define END_INSTR 4
  118. #define DELETED_INSTR 5
  119. STATIC add_end()
  120. {
  121. /* Add an end-pseudo to the current instruction list */
  122. lastline->l_next = newline(OPNO);
  123. lastline = lastline->l_next;
  124. lastline->l_instr = ps_end;
  125. }
  126. process_lines(fout)
  127. FILE* fout;
  128. {
  129. line_p lnp;
  130. short instr;
  131. bool eof;
  132. /* Read and process the code contained in the current file,
  133. * on a per procedure basis.
  134. * On the fly, fragments are formed. Recall that two
  135. * successive CON pseudos are allocated consecutively
  136. * in a single fragment, unless these CON pseudos are
  137. * separated in the assembly language program by one
  138. * of: ROM, BSS, HOL and END (and of course EndOfFile).
  139. * The same is true for ROM pseudos.
  140. * We keep track of a fragment type (DROM after a ROM
  141. * pseudo, DCON after a CON and DUNKNOWN after a HOL,
  142. * BSS, END or EndOfFile) and a fragment number (which
  143. * is incremented every time we enter a new fragment).
  144. * Every data block is assigned such a number
  145. * when we come accross its defining occurrence.
  146. */
  147. eof = FALSE;
  148. firstline = (line_p)0;
  149. lastline = (line_p)0;
  150. while (!eof)
  151. {
  152. linecount++; /* for error messages */
  153. switch (readline(&instr, &lnp))
  154. {
  155. /* read one line, see what kind it is */
  156. case WITH_OPERAND:
  157. /* instruction with operand, e.g. LOL 10 */
  158. lnp = readoperand(instr);
  159. lnp->l_instr = instr;
  160. /* Fall through! */
  161. case NORMAL:
  162. VL(lnp);
  163. if (lastline != (line_p)0)
  164. {
  165. lastline->l_next = lnp;
  166. }
  167. lastline = lnp;
  168. break;
  169. case EOFILE:
  170. eof = TRUE;
  171. fragm_type = DUNKNOWN;
  172. if (firstline != (line_p)0)
  173. {
  174. add_end();
  175. putlines(firstline, fout);
  176. firstline = (line_p)0;
  177. }
  178. break;
  179. case PRO_INSTR:
  180. VL(lnp);
  181. labelcount = 0;
  182. if (firstline != lnp)
  183. {
  184. /* If PRO is not the first
  185. * instruction:
  186. */
  187. add_end();
  188. putlines(firstline, fout);
  189. firstline = lnp;
  190. }
  191. lastline = lnp;
  192. break;
  193. case END_INSTR:
  194. curproc->p_nrformals = mespar;
  195. mespar = UNKNOWN_SIZE;
  196. assert(lastline != (line_p)0);
  197. lastline->l_next = lnp;
  198. putlines(firstline, fout);
  199. /* write and delete code */
  200. firstline = (line_p)0;
  201. lastline = (line_p)0;
  202. cleaninstrlabs();
  203. /* scope of instruction labels ends here,
  204. * so forget about them.
  205. */
  206. fragm_type = DUNKNOWN;
  207. break;
  208. case DELETED_INSTR:
  209. /* EXP, INA etc. are deleted */
  210. break;
  211. default:
  212. error("illegal readline");
  213. }
  214. }
  215. }
  216. int readline(instr_out, lnp_out) short* instr_out;
  217. line_p* lnp_out;
  218. {
  219. register line_p lnp;
  220. short n;
  221. /* Read one line. If it is a normal EM instruction without
  222. * operand, we can allocate a line struct for it here.
  223. * If so, return a pointer to it via lnp_out, else just
  224. * return the instruction code via instr_out.
  225. */
  226. VA((short*)instr_out);
  227. VA((short*)lnp_out);
  228. switch (table1())
  229. {
  230. /* table1 sets string, tabval or tabval2 and
  231. * returns an indication of what was read.
  232. */
  233. case ATEOF:
  234. return EOFILE;
  235. case INST:
  236. *instr_out = tabval; /* instruction code */
  237. return WITH_OPERAND;
  238. case DLBX:
  239. /* data label defining occurrence, precedes
  240. * a data block.
  241. */
  242. db = block_of_lab(string);
  243. /* global variable, used by inpseudo */
  244. lnp = newline(OPSHORT);
  245. SHORT(lnp) = (short)db->d_id;
  246. lnp->l_instr = ps_sym;
  247. *lnp_out = lnp;
  248. if (firstline == (line_p)0)
  249. {
  250. firstline = lnp;
  251. /* only a pseudo (e.g. PRO) or data label
  252. * can be the first instruction.
  253. */
  254. }
  255. return NORMAL;
  256. case ILBX:
  257. /* instruction label defining occurrence */
  258. labelcount++;
  259. lnp = newline(OPINSTRLAB);
  260. lnp->l_instr = op_lab;
  261. INSTRLAB(lnp) = instr_lab(tabval);
  262. *lnp_out = lnp;
  263. return NORMAL;
  264. case PSEU:
  265. n = tabval;
  266. lnp = inpseudo(n); /* read a pseudo */
  267. if (n == ps_hol)
  268. n = ps_bss;
  269. if (lnp == (line_p)0)
  270. return DELETED_INSTR;
  271. *lnp_out = lnp;
  272. lnp->l_instr = n;
  273. if (firstline == (line_p)0)
  274. {
  275. firstline = lnp;
  276. /* only a pseudo (e.g. PRO) or data label
  277. * can be the first instruction.
  278. */
  279. }
  280. if (n == ps_end)
  281. return END_INSTR;
  282. if (n == ps_pro)
  283. return PRO_INSTR;
  284. return NORMAL;
  285. }
  286. /* NOTREACHED */
  287. }
  288. line_p readoperand(instr) short instr;
  289. {
  290. /* Read the operand of the given instruction.
  291. * Create a line struct and return a pointer to it.
  292. */
  293. register line_p lnp;
  294. short flag;
  295. VI(instr);
  296. flag = em_flag[instr - sp_fmnem] & EM_PAR;
  297. if (flag == PAR_NO)
  298. {
  299. return (newline(OPNO));
  300. }
  301. switch (table2())
  302. {
  303. case sp_cend:
  304. return (newline(OPNO));
  305. case CSTX1:
  306. /* constant */
  307. /* If the instruction has the address
  308. * of an external variable as argument,
  309. * the constant must be regarded as an
  310. * offset in the current hol block,
  311. * so an object must be created.
  312. * Similarly, the instruction may have
  313. * an instruction label as argument.
  314. */
  315. switch (flag)
  316. {
  317. case PAR_G:
  318. lnp = newline(OPOBJECT);
  319. OBJ(lnp) = object(curhol, (offset)tabval,
  320. opr_size(instr));
  321. break;
  322. case PAR_B:
  323. lnp = newline(OPINSTRLAB);
  324. INSTRLAB(lnp) = instr_lab(tabval);
  325. break;
  326. default:
  327. lnp = newline(OPSHORT);
  328. SHORT(lnp) = tabval;
  329. break;
  330. }
  331. break;
  332. #ifdef LONGOFF
  333. case CSTX2:
  334. /* double constant */
  335. if (flag == PAR_G)
  336. {
  337. lnp = newline(OPOBJECT);
  338. OBJ(lnp) = object(curhol, tabval2,
  339. opr_size(instr));
  340. break;
  341. }
  342. lnp = newline(OPOFFSET);
  343. OFFSET(lnp) = tabval2;
  344. break;
  345. #endif
  346. case ILBX:
  347. /* applied occurrence instruction label */
  348. lnp = newline(OPINSTRLAB);
  349. INSTRLAB(lnp) = instr_lab(tabval);
  350. break;
  351. case DLBX:
  352. /* applied occurrence data label */
  353. lnp = newline(OPOBJECT);
  354. OBJ(lnp) = object(string, (offset)0,
  355. opr_size(instr));
  356. break;
  357. case VALX1:
  358. lnp = newline(OPOBJECT);
  359. OBJ(lnp) = object(string, (offset)tabval,
  360. opr_size(instr));
  361. break;
  362. #ifdef LONGOFF
  363. case VALX2:
  364. lnp = newline(OPOBJECT);
  365. OBJ(lnp) = object(string, tabval2,
  366. opr_size(instr));
  367. break;
  368. #endif
  369. case sp_pnam:
  370. lnp = newline(OPPROC);
  371. PROC(lnp) = proclookup(string, OCCURRING);
  372. VP(PROC(lnp));
  373. break;
  374. default:
  375. assert(FALSE);
  376. }
  377. return lnp;
  378. }
  379. static char* hol_label()
  380. {
  381. static int holno;
  382. line_p lnp;
  383. extern char* lastname;
  384. /* Create a label for a hol pseudo, so that it can be converted
  385. * into a bss. The label is appended to the list of instructions.
  386. */
  387. sprintf(string, "_HH%d", ++holno);
  388. symlookup(string, OCCURRING); /* to make it exa */
  389. db = block_of_lab(string);
  390. lnp = newline(OPSHORT);
  391. SHORT(lnp) = (short)db->d_id;
  392. lnp->l_instr = ps_sym;
  393. if (firstline == (line_p)0)
  394. {
  395. firstline = lnp;
  396. }
  397. if (lastline != (line_p)0)
  398. {
  399. lastline->l_next = lnp;
  400. }
  401. lastline = lnp;
  402. return lastname;
  403. }
  404. line_p inpseudo(n) short n;
  405. {
  406. int m;
  407. line_p lnp;
  408. byte pseu;
  409. short nlast;
  410. /* Read the (remainder of) a pseudo instruction, the instruction
  411. * code of which is n. The END pseudo may be deleted (return 0).
  412. * The pseudos INA, EXA, INP and EXP (visibility pseudos) must
  413. * also be deleted, although the effects they have on the
  414. * visibility of global names and procedure names must first
  415. * be recorded in the datablock or procedure table.
  416. */
  417. switch (n)
  418. {
  419. case ps_hol:
  420. /* hol pseudos are carefully converted into bss
  421. * pseudos, so that the IL phase will not be
  422. * bothered by this. Also, references to the ABS
  423. * block will still work when passed through EGO.
  424. */
  425. if (lastline != (line_p)0 && is_datalabel(lastline))
  426. {
  427. extern char* lastname;
  428. curhol = lastname;
  429. }
  430. else
  431. {
  432. curhol = hol_label();
  433. }
  434. n = ps_bss;
  435. /* fall through */
  436. case ps_bss:
  437. case ps_rom:
  438. case ps_con:
  439. if (lastline == (line_p)0 || !is_datalabel(lastline))
  440. {
  441. assert(lastline != (line_p)0);
  442. nlast = INSTR(lastline);
  443. if (n == nlast && (n == ps_rom || n == ps_con))
  444. {
  445. /* Two successive roms/cons are
  446. * combined into one data block
  447. * if the second is not preceded by
  448. * a data label.
  449. */
  450. lnp = arglist(0);
  451. pseu = (byte)(n == ps_rom ? DROM : DCON);
  452. combine(db, lastline, lnp, pseu);
  453. oldline(lnp);
  454. return (line_p)0;
  455. }
  456. else
  457. {
  458. error("datablock without label");
  459. }
  460. }
  461. VD(db);
  462. m = (n == ps_bss ? 3 : 0);
  463. lnp = arglist(m);
  464. /* Read the arguments, 3 for hol or bss and a list
  465. * of undetermined length for rom and con.
  466. */
  467. dblockdef(db, n, lnp);
  468. /* Fill in d_pseudo, d_size and d_values fields of db */
  469. if (fragm_type != db->d_pseudo)
  470. {
  471. /* Keep track of fragment numbers,
  472. * enter a new fragment.
  473. */
  474. fragm_nr++;
  475. switch (db->d_pseudo)
  476. {
  477. case DCON:
  478. case DROM:
  479. fragm_type = db->d_pseudo;
  480. break;
  481. default:
  482. fragm_type = DUNKNOWN;
  483. break;
  484. }
  485. }
  486. db->d_fragmnr = fragm_nr;
  487. return lnp;
  488. case ps_ina:
  489. getsym(DEFINING);
  490. /* Read and lookup a symbol. As this must be
  491. * the first occurrence of the symbol and we
  492. * say it's a defining occurrence, getsym will
  493. * automatically make it internal (according to
  494. * the EM visibility rules).
  495. * The result (a dblock pointer) is voided.
  496. */
  497. return (line_p)0;
  498. case ps_inp:
  499. getproc(DEFINING); /* same idea */
  500. return (line_p)0;
  501. case ps_exa:
  502. getsym(OCCURRING);
  503. return (line_p)0;
  504. case ps_exp:
  505. getproc(OCCURRING);
  506. return (line_p)0;
  507. case ps_pro:
  508. curproc = getproc(DEFINING);
  509. /* This is a real defining occurrence of a proc */
  510. curproc->p_localbytes = get_off();
  511. curproc->p_flags1 |= PF_BODYSEEN;
  512. /* Record the fact that we came accross
  513. * the body of this procedure.
  514. */
  515. lnp = newline(OPPROC);
  516. PROC(lnp) = curproc;
  517. lnp->l_instr = (byte)ps_pro;
  518. return lnp;
  519. case ps_end:
  520. curproc->p_nrlabels = labelcount;
  521. lnp = newline(OPNO);
  522. get_off();
  523. /* Void # localbytes, which we already know
  524. * from the PRO instruction.
  525. */
  526. return lnp;
  527. case ps_mes:
  528. lnp = arglist(0);
  529. switch ((int)aoff(ARG(lnp), 0))
  530. {
  531. case ms_err:
  532. error("ms_err encountered");
  533. case ms_opt:
  534. error("ms_opt encountered");
  535. case ms_emx:
  536. ws = aoff(ARG(lnp), 1);
  537. ps = aoff(ARG(lnp), 2);
  538. break;
  539. case ms_ext:
  540. /* this message was already processed
  541. * by the lib package
  542. */
  543. case ms_src:
  544. /* Don't bother about linecounts */
  545. oldline(lnp);
  546. return (line_p)0;
  547. case ms_par:
  548. mespar = aoff(ARG(lnp), 1);
  549. /* #bytes of parameters of current proc */
  550. break;
  551. }
  552. return lnp;
  553. default:
  554. assert(FALSE);
  555. }
  556. /* NOTREACHED */
  557. }