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