1 /* $Id: top.c,v 1.12 1994/06/24 13:29:07 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".
11 /* STANDARD MACHINE-INDEPENT C CODE *************/
13 extern char *lstrip();
14 extern instr_p newinstr();
15 extern instr_p read_instr();
16 extern instr_p gen_instr();
17 extern char * malloc();
18 extern char *strcat();
19 extern char *strcpy();
20 extern char *strncpy();
22 struct variable var[NRVARS+1];
23 struct variable ANY; /* ANY symbol matching any instruction */
25 char *REST; /* Opcode of first instruction not matched by current pattern */
30 /* Macros for efficiency: */
32 #define is_white(c) ( (c) == ' ' || (c) == '\t')
34 /* Skip white space in the unprocessed part of instruction 'ip' */
35 #define skip_white(ip) while (is_white(*(ip)->rest_line)) (ip)->rest_line++
44 /* Optimize the standard input.
45 * The optimizer uses a moving window. The instructions in the current
46 * window are matched against a set of patterns generated from the
47 * machine description table. If the match fails, the first instruction of
48 * the window is moved to a back-up queue and a new instruction is
49 * read from the input and appended to the end of the window.
50 * If a matching pattern is found (and its operands etc. are ok),
51 * the instructions at the head of the window are replaced by new
52 * instructions, as indicated in the descriptor table; a new window
53 * is created, consisting of the back-up instructions and the new
54 * instructions and the rest of the old window. So effectively the
55 * window moves a bit to the left after every hit. Hence sequences of
57 * movl r0,x ; cmpl $0,x -> movl r0,x ; tstl x -> movl r0,x
58 * are captured without having a separate pattern for "movl ; cmpl".
60 * Whenever the backup queue exceeds some threshold, its first instruction
61 * is written to the output and is removed.
66 struct queue_t windowq, backupq;
74 fill_window(window,MIN_WINDOW_SIZE);
75 while (!empty(window)) {
76 if (try_hashentry(hashtab[hash(window)],window) ||
77 try_hashentry(hashany,window)) {
78 join_queues(backup,window);
83 if (qlength(backup) > MIN_WINDOW_SIZE) {
87 fill_window(window,MIN_WINDOW_SIZE);
89 while (!empty(backup)) write_first(backup);
94 bool try_hashentry(list,window)
101 for (pp = list; *pp != -1; pp++) {
103 if (check_pattern(p,window) &&
104 check_operands(p,window) &&
105 check_constraint(*pp)) {
122 return ip->opc[0] % 31;
135 /* for (sum=0,p=ip->opc;*p;p++)
139 for (sum=i=0,p=ip->opc;*p;i += 3)
140 sum += (*p++)<<(i&03);
144 /* Fill the working window until it contains at least 'len' items.
145 * When end-of-file is encountered it may contain fewer items.
153 while(qlength(w) < len) {
154 if ((ip = read_instr()) == NIL) break;
155 ip->rest_line = ip->line;
164 register instr_p ip = qhead(w);
166 fputs(ip->line, stdout);
172 /* Try to recognize the opcode part of an instruction */
180 if (ip->state == JUNK) return;
183 if (*p == LABEL_STARTER) {
184 strcpy(ip->opc,"labdef");
185 ip->state = ONLY_OPC;
189 qlim = q + MAX_OPC_LEN;
190 while(*p != OPC_TERMINATOR && *p != '\n') {
199 ip->state = (well_shaped(ip->opc) ? ONLY_OPC : JUNK);
204 /* Check if pattern 'p' matches the current input */
206 bool check_pattern(p,w)
210 register idescr_p id_p;
215 ANY.vstate = UNINSTANTIATED;
216 idlim = &p->pat[p->patlen];
217 for (id_p = p->pat; id_p < idlim; id_p++) {
218 if (ip == NIL || ip->state == JUNK) return FALSE;
219 if (id_p->opcode == (char *) 0) {
222 if (strcmp(ip->opc,id_p->opcode) != 0) return FALSE;
232 bool check_operands(p,w)
237 register idescr_p id_p;
240 /* fprintf(stderr,"try pattern %d\n",p-patterns); */
242 for (id_p = p->pat, ip = qhead(w); id_p < &p->pat[p->patlen];
243 id_p++, ip = next(ip)) {
245 if (ip->state == JUNK ||
246 (ip->state == ONLY_OPC && !split_operands(ip))) {
249 for (n = 0; n < MAXOP; n++) {
250 if (!opmatch(&id_p->templates[n],ip->op[n])) {
255 /* fprintf(stderr,"yes\n"); */
261 /* Reset all variables to uninstantiated */
267 for (v = 1; v <= NRVARS; v++) var[v].vstate = UNINSTANTIATED;
271 /* See if operand 's' matches the operand described by template 't'.
272 * As a side effect, any uninstantiated variables used in the
273 * template may become instantiated. For such a variable we also
274 * check if it satisfies the constraint imposed on it in the
275 * mode-definitions part of the table.
282 char *l, buf[MAXOPLEN+1];
283 bool was_instantiated;
287 if (vno == -1 || s[0] == '\0' ) {
288 return (vno == -1 && s[0] == '\0');
290 was_instantiated = (var[vno].vstate == INSTANTIATED);
292 if ( (l=lstrip(buf,t->lctxt)) != NULLSTRING && rstrip(l,t->rctxt)) {
293 return (vno == 0 && *l == '\0') ||
294 (vno != 0 && unify(l,&var[vno]) &&
295 (was_instantiated || tok_chk(vno)));
302 /* Try to recognize the operands of an instruction */
304 bool split_operands(ip)
310 if (strcmp(ip->opc,"labdef") ==0) {
313 for (i = 0; operand(ip,i) && op_separator(ip); i++);
315 res = remainder_empty(ip);
316 ip->state = (res ? DONE : JUNK);
329 while( *p != LABEL_TERMINATOR) p++;
330 oplen = p - ip->rest_line;
331 if (oplen == 0 || oplen > MAXOPLEN) return;
332 strncpy(ip->op[0],ip->rest_line,oplen);
333 ip->op[0][oplen] = '\0';
341 /* Try to recognize the next operand of instruction 'ip' */
356 while((*p != OP_SEPARATOR || nesting) && *p != '\n') {
358 if (strindex(PAREN_OPEN, *p) != 0) nesting++;
359 else if (strindex(PAREN_CLOSE, *p) != 0) nesting--;
363 oplen = p - ip->rest_line;
364 if (oplen == 0 || oplen > MAXOPLEN) return FALSE;
365 strncpy(ip->op[n],ip->rest_line,oplen);
366 ip->op[n][oplen] = '\0';
376 /* See if the unprocessed part of instruction 'ip' is empty
377 * (or contains only white space).
380 bool remainder_empty(ip)
384 return *ip->rest_line == '\n';
388 /* Try to match 'ctxt' at the beginning of string 'str'. If this
389 * succeeds then return a pointer to the rest (unmatched part) of 'str'.
392 char *lstrip(str,ctxt)
393 register char *str, *ctxt;
395 assert(ctxt != NULLSTRING);
396 while (*str != '\0' && *str == *ctxt) {
400 return (*ctxt == '\0' ? str : NULLSTRING);
405 /* Try to match 'ctxt' at the end of 'str'. If this succeeds then
406 * replace truncate 'str'.
409 bool rstrip(str,ctxt)
412 register char *s, *c;
414 for (s = str; *s != '\0'; s++);
415 for (c = ctxt; *c != '\0'; c++);
417 if (s < str || *s != *c--) return FALSE;
425 /* Try to unify variable 'v' with string 'str'. If the variable
426 * was instantiated the unification only succeeds if the variable
427 * and the string match; else the unification succeeds and the
428 * variable becomes instantiated to the string.
433 register struct variable *v;
435 if (v->vstate == UNINSTANTIATED) {
436 v->vstate = INSTANTIATED;
437 strcpy(v->value,str);
440 return strcmp(v->value,str) == 0;
446 /* Transform the working window according to pattern 'p' */
455 for (i = 0; i < p->patlen; i++) {
465 /* Generate the replacement for pattern 'p' and insert it
466 * at the front of the working window.
467 * Note that we generate instructions in reverser order.
471 register patdescr_p p;
474 register idescr_p id_p;
476 for (id_p = &p->repl[p->replen-1]; id_p >= p->repl; id_p--) {
477 insert(w,gen_instr(id_p));
483 /* Generate an instruction described by 'id_p'.
484 * We build a 'line' for the new instruction and call set_opcode()
485 * to re-recognize its opcode. Hence generated instructions are treated
486 * in exactly the same way as normal instructions that are just read in.
489 instr_p gen_instr(id_p)
498 static char tmp[] = "x";
503 if (opc == (char *) 0) opc = ANY.value;
504 if (strcmp(opc,"labdef") == 0) {
509 tmp[0] = OPC_TERMINATOR;
513 for (n = 0; n < MAXOP;) {
514 t = &id_p->templates[n++];
515 if (t->varno == -1) break;
517 if (t->varno != 0) strcat(s,var[t->varno].value);
519 if (n<MAXOP && id_p->templates[n].varno!=-1) {
520 tmp[0] = OP_SEPARATOR;
525 tmp[0] = LABEL_TERMINATOR;
529 ip->rest_line = ip->line;
536 /* Reading and writing instructions.
537 * An instruction is assumed to be on one line. The line
538 * is copied to the 'line' field of an instruction struct,
539 * terminated by a \n and \0. If the line is too long (>MAXLINELEN),
540 * it is split into pieces of length MAXLINELEN and the state of
541 * each such struct is set to JUNK (so it will not be optimized).
544 static bool junk_state = FALSE; /* TRUE while processing a very long line */
551 register FILE *inp = stdin;
555 plim = &ip->line[MAXLINELEN];
556 if (( c = getc(inp)) == EOF) return NIL;
557 for (p = ip->line; p < plim;) {
561 if (junk_state) ip->state = JUNK;
569 junk_state = ip->state = JUNK;
576 * As all instruction struct have the same size we can re-use every struct.
577 * We maintain a pool of free instruction structs.
580 static instr_p instr_pool;
581 int nr_mallocs = 0; /* for statistics */
588 if (instr_pool == NIL) {
589 instr_pool = (instr_p) malloc(sizeof(struct instruction));
593 assert(instr_pool != NIL);
595 instr_pool = instr_pool->fw;
596 ip->fw = ip->bw = NIL;
597 ip->rest_line = NULLSTRING;
598 ip->line[0] = ip->opc[0] = '\0';
599 ip->state = ONLY_OPC;
600 for (i = 0; i < MAXOP; i++) ip->op[i][0] = '\0';
613 /* Debugging stuff */
615 badassertion(file,line)
619 fprintf(stderr,"assertion failed file %s, line %u\n",file,line);
628 fprintf(stderr,"\n");
634 /* Low level routines */
636 bool op_separator(ip)
640 if (*(ip->rest_line) == OP_SEPARATOR) {
650 bool well_shaped(opc)
653 return is_letter(opc[0]);
659 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
662 /* is_white(c) : turned into a macro, see beginning of file */