1 /* $Id: ic_lookup.c,v 1.12 1994/06/24 10:24:23 ceriel Exp $ */
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".
6 /* I N T E R M E D I A T E C O D E
8 * I C _ L O O K U P . C
14 #include "../share/types.h"
15 #include "../share/debug.h"
16 #include "../share/map.h"
18 #include "ic_lookup.h"
19 #include "../share/alloc.h"
22 sym_p symhash[NSYMHASH];
23 prc_p prochash[NPROCHASH];
24 num_p numhash[NNUMHASH];
27 extern char *strcpy();
29 #define newsym() (sym_p) newstruct(sym)
30 #define newprc() (prc_p) newstruct(prc)
31 #define newnum() (num_p) newstruct(num)
33 #define oldsym(x) oldstruct(sym,x)
34 #define oldprc(x) oldstruct(prc,x)
35 #define oldnum(x) oldstruct(num,x)
46 lab_id instr_lab(number)
49 register num_p *npp, np;
51 /* In EM assembly language, a label is an unsigned number,
52 * e.g. 120 in 'BRA *120'. In IC the labels of a procedure
53 * are represented by consecutive integer numbers, called
54 * lab_id. The mapping takes place here.
58 npp = &numhash[number%NNUMHASH];
59 while (*npp != (num_p) 0) {
60 if ((*npp)->n_number == number) {
61 return(*npp)->n_labid;
63 npp = &(*npp)->n_next;
67 /* The label was not found in the hashtable, so
68 * create a new entry for it.
72 np->n_number = number;
73 np->n_labid = ++lastlid;
74 /* Assign a new label identifier to the num struct.
75 * lastlid is reset to 0 at the beginning of
76 * every new EM procedure (by cleaninstrlabs).
85 STATIC unsigned hash(string) char *string; {
87 register unsigned i,sum;
89 for (sum=i=0,p=string;*p;i += 3)
90 sum ^= (*p++)<<(i&07);
94 dblock_p symlookup(name, status)
98 /* Look up the name of a data block. The name can appear
99 * in either a defining or applied occurrence (status is
100 * DEFINING, OCCURRING resp.), or in a MES ms_ext instruction
101 * as the name of a data block imported by a library module
102 * (status is IMPORTING). Things get complicated,
103 * because a HOL pseudo need not be preceded by a
104 * data label, i.e. a hol block need not have a name.
108 register sym_p *spp, sp;
109 register dblock_p dp;
111 if (name == (char *) 0) {
112 assert(status == DEFINING);
115 spp = &symhash[hash(name)%NSYMHASH];
116 while (*spp != (sym_p) 0) {
117 /* Every hashtable entry points to a list
118 * of synonyms (i.e. names with the same
119 * hash values). Try to find 'name' in its
122 if (strcmp((*spp)->sy_name, name) == 0) {
123 dp = (*spp)->sy_dblock;
124 if (status != DEFINING ||
125 (dp->d_flags1 & DF_EXTERNAL) == 0) {
126 dp->d_flags2 |= DF_FILE;
128 if (dp->d_flags2 & DF_FILE) {
129 lastname = (*spp)->sy_name;
134 spp = &(*spp)->sy_next;
137 /* The name is not found, so create a new entry for it.
138 * However, if the status is IMPORTING, we just return 0,
139 * indicating that we don't need this name.
141 if (status == IMPORTING) return (dblock_p) 0;
145 sp->sy_name = (char *) newcore(strlen(name)+1);
146 strcpy(sp->sy_name, name);
147 lastname = sp->sy_name; /* quick hack to get at
150 dp = sp->sy_dblock = newdblock();
152 if (fdblock == (dblock_p) 0) {
154 /* first data block */
156 ldblock->d_next = dp; /* link to last dblock */
159 dp->d_pseudo = DUNKNOWN; /* clear all fields */
160 dp->d_id = ++lastdid;
162 dp->d_objlist = (obj_p) 0;
163 dp->d_values = (arg_p) 0;
164 dp->d_next = (dblock_p) 0;
167 if (status == OCCURRING) {
168 /* This is the first occurrence of the identifier,
169 * so if it is a used occurrence make the
170 * identifier externally visible, else make it
173 dp->d_flags1 |= DF_EXTERNAL;
175 dp->d_flags2 |= DF_FILE;
183 dblock_p getsym(status)
186 if (table2() != DLBX) {
187 error("symbol expected");
189 return(symlookup(string,status));
196 proc_p getproc(status)
199 if (table2() != sp_pnam) {
200 error("proc name expected");
202 return(proclookup(string,status));
209 proc_p proclookup(name, status)
213 register prc_p *ppp, pp;
216 ppp = &prochash[hash(name)%NPROCHASH];
217 while (*ppp != (prc_p) 0) {
218 /* Every hashtable entry points to a list
219 * of synonyms (i.e. names with the same
220 * hash values). Try to find 'name' in its
223 if (strcmp((*ppp)->pr_name, name) == 0) {
225 dp = (*ppp)->pr_proc;
226 if (status != DEFINING ||
227 (dp->p_flags1 & PF_EXTERNAL) == 0) {
228 dp->p_flags2 |= PF_FILE;
231 if (dp->p_flags2 & PF_FILE) return dp;
234 ppp = &(*ppp)->pr_next;
237 /* The name is not found, so create a new entry for it,
238 * unless the status is IMPORTING, in which case we
239 * return 0, indicating we don't want this proc.
241 if (status == IMPORTING) return (proc_p) 0;
245 pp->pr_name = (char *) newcore(strlen(name)+1);
246 strcpy(pp->pr_name, name);
247 dp = pp->pr_proc = newproc();
248 if (fproc == (proc_p) 0) {
249 fproc = dp; /* first proc */
254 dp->p_id = ++lastpid; /* create a unique proc_id */
255 dp->p_next = (proc_p) 0;
258 if (status == OCCURRING) {
259 /* This is the first occurrence of the identifier,
260 * so if it is a used occurrence the make the
261 * identifier externally visible, else make it
264 dp->p_flags1 |= PF_EXTERNAL;
266 dp->p_flags2 |= PF_FILE;
276 register num_p *npp, np, next;
278 for (npp = numhash; npp < &numhash[NNUMHASH]; npp++) {
279 for (np = *npp; np != (num_p) 0; np = next) {
285 /* Reset last label id (used by instr_lab). */
286 lastlid = (lab_id) 0;
293 dump_procnames(hash,n,f)
298 /* Save the names of the EM procedures in file f.
299 * Note that the Optimizer Intermediate Code does not
300 * use identifiers but proc_ids, object_ids etc.
301 * The names, however, can be used after optimization
302 * is completed, to reconstruct Compact Assembly Language.
303 * The output consists of tuples (proc_id, name).
304 * This routine is called once for every input file.
305 * To prevent names of external procedures being written
306 * more than once, the PF_WRITTEN flag is used.
309 register prc_p *pp, ph;
312 #define PF_WRITTEN 01
315 for (pp = &hash[0]; pp < &hash[n]; pp++) {
316 /* Traverse the entire hash table */
317 for (ph = *pp; ph != (prc_p) 0; ph = ph->pr_next) {
318 /* Traverse the list of synonyms */
320 if ((p->p_flags2 & PF_WRITTEN) == 0) {
321 /* not been written yet */
322 fprintf(f,"%d %s\n",p->p_id, ph->pr_name);
323 p->p_flags2 |= PF_WRITTEN;
331 cleanprocs(hash,n,mask)
335 /* After an EM input file has been processed, the names
336 * of those procedures that are internal (i.e. not visible
337 * outside the file they are defined in) must be removed
338 * from the procedure hash table. This is accomplished
339 * by removing the 'prc struct' from its synonym list.
340 * After the final input file has been processed, all
341 * remaining prc structs are also removed.
344 register prc_p *pp, ph, x, next;
346 for (pp = &hash[0]; pp < &hash[n]; pp++) {
347 /* Traverse the hash table */
349 for (ph = *pp; ph != (prc_p) 0; ph = next) {
350 /* Traverse the synonym list.
351 * x points to the prc struct just before ph,
352 * or is 0 if ph is the first struct of
355 ph->pr_proc->p_flags2 &= ~PF_FILE;
357 if ((ph->pr_proc->p_flags1 & mask) == 0) {
358 if (x == (prc_p) 0) {
363 oldprc(ph); /* delete the struct */
373 /* dump_dblocknames */
375 dump_dblocknames(hash,n,f)
380 /* Save the names of the EM data blocks in file f.
381 * The output consists of tuples (dblock_id, name).
382 * This routine is called once for every input file.
385 register sym_p *sp, sh;
388 #define DF_WRITTEN 01
391 for (sp = &hash[0]; sp < &hash[n]; sp++) {
392 /* Traverse the entire hash table */
393 for (sh = *sp; sh != (sym_p) 0; sh = sh->sy_next) {
394 /* Traverse the list of synonyms */
396 if ((d->d_flags2 & DF_WRITTEN) == 0) {
397 /* not been written yet */
398 fprintf(f,"%d %s\n",d->d_id, sh->sy_name);
399 d->d_flags2 |= DF_WRITTEN;
407 cleandblocks(hash,n,mask)
411 /* After an EM input file has been processed, the names
412 * of those data blocks that are internal must be removed.
415 register sym_p *sp, sh, x, next;
417 for (sp = &hash[0]; sp < &hash[n]; sp++) {
419 for (sh = *sp; sh != (sym_p) 0; sh = next) {
421 sh->sy_dblock->d_flags2 &= ~DF_FILE;
422 if ((sh->sy_dblock->d_flags1 & mask) == 0) {
423 if (x == (sym_p) 0) {
428 oldsym(sh); /* delete the struct */