ic.c 13 KB

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