ic.c 13 KB

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