/* $Id$ */
/*
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 */
/*  S H O W . C  */

/* This program can be used to make the output of the 'cf' pass
 * human readable. It will display either the procedure table,
 * the datablock table, the basic block table or the EM text,
 * depending on the flag that is passed as first argument.
 */



#include <stdio.h>
#include <em_spec.h>
#include <em_pseu.h>
#include "types.h"
#include "def.h"
#include "global.h"


#define BMASK 0377






#define space1()	printf("	")
char format[] = "	%-11s%d\n";
char lformat[] = "	%-11s%ld\n";
char sformat[] = "	%-10s%s\n";
char dformat[] = "		%-11s%d\n";
char oformat[] = "		%-11s%ld\n";



FILE *f;	/* input file */


#define getbyte()	getc(f)

short getshort()
{
	register n;

	n = getbyte();
	n |= getbyte() << 8;
	return n;
}

offset getoff()
{
	register offset n;

	n = getshort() & 0xFFFF;
	n |= ((offset) getshort() ) << 16;
	return n;
}


int getint()
{
	/* Read an integer from the input file. This routine is
	 * only used when reading a bitvector-set. We expect  an
	 * integer to be either a short or a long.
	 */

	if (sizeof(int) == sizeof(short)) {
		return getshort();
	} else {
		return getoff();
	}
}


/* VARARGS 1 */
error(s,a) char *s,*a; {

	fprintf(stderr,"error");
	fprintf(stderr,": ");
	fprintf(stderr,s,a);
	fprintf(stderr,"\n");
	exit(-1);
}

main(argc, argv)
	int argc;
	char *argv[];
{
	if (argc != 3 || argv[1][0] != '-') {
		error("usage: %s -[ldpbc] filename",argv[0]);
	}
	if ((f = fopen(argv[2], "rb")) == NULL) {
		error("cannot open %s", argv[2]);
	}
	switch(argv[1][1]) {
		case 'l':
			showl();
			break;
		case 'd':
			showd();
			break;
		case 'p':
			showp();
			break;
		case 'b':
			showb();
			break;
		case 'c':
			showc();
			break;
		default:
			error("bad flag");
	}

	fclose(f);
	exit(0);
}


showcset()
{
	/* print a compact (bitvector) set */

	short size;
	register short i,j;
	int w, mask;

	size = getshort();
	/* # significant bits in bitvector */
	i = 1;
	printf(" { ");
	if (size == 0) {
		printf("}\n");
		return;
	}
	for (;;) {
		w = getint();
		mask = 1 ;
		for (j = 1; j <= sizeof(int)*8; j++) {
			if (w & mask) {
				printf("%d ",i);
			}
			if (i++ == size) {
				printf ("}\n");
				return;
			}
			mask <<=  1;
		}
	}
}



showp()
{
	byte b;
	short n;
	short all;
	printf("total number of procs: %d\n\n",getshort());
	all = getshort();
	while (TRUE) {
		n = getshort();
		if (feof(f)) break;
		printf("PROC\n");
		printf(format,"id =",n);
		printf(format,"flags1 =",b = getbyte());
		if (b & PF_BODYSEEN) {
			printf(format,"# labels =",getshort());
			printf(lformat,"# locals =",getoff());
			printf(lformat,"# formals =",getoff());
			if (all == 1) {
				printf("	changed ="); showcset();
				printf(format,"c_flags =",getshort());
				printf(format,"u_flags =",getshort());
				printf("	calling ="); showcset();
			}
		} else {
			printf("	body not available\n");
		}
	}
}


char *pseudo[5] = {"hol", "bss", "rom", "con", "unknown" };

showd()
{
	short n;
	printf("total number of objects: %d\n\n",getshort());
	while (TRUE) {
		n = getbyte();
		if (feof(f)) break;
		switch(n) {
			case MARK_DBLOCK:
				printf("DBLOCK\n");
				printf(format,"id =",getshort());
				printf(sformat,"pseudo =",
					pseudo[(short) getbyte()]);
				printf(lformat,"size =",getoff());
				printf(format,"fragment =",getshort());
				printf(format,"flags1 =",
					(short) getbyte());
				break;
			case MARK_OBJ:
				printf("	OBJ\n");
				space1();
				printf(format,"id =",getshort());
				space1();
				printf(lformat,"size =",getoff());
				space1();
				printf(lformat,"offset =",getoff());
				break;
			case MARK_ARG:
				printf("	VALUE\n");
				space1();
				printf(lformat,"offset =",getoff());
				break;
		}
	}
}


/* The mnemonics of the EM instructions and pseudos */


extern char em_mnem[];
extern char em_pseu[];
char lab_mnem[] = "instrlab";
char sym_mnem[] = "datalab";

showinstr()
{
	short instr;
	char *s;

	instr = (short) getbyte();
	if (feof(f)) return FALSE;
	if (instr >= sp_fmnem && instr <= sp_lmnem) {
		s = &(em_mnem[(instr-sp_fmnem) *4]);
	} else {
		if (instr == op_lab) {
			s = lab_mnem;
		} else {
			if (instr == ps_sym) {
				s = sym_mnem;
			} else {
				s = &(em_pseu[(instr-sp_fpseu)*4]);
			}
		}
	}
	printf("%s",s);
	switch((short) getbyte()) {
		case OPSHORT:
		case OPOBJECT:
			printf(" %d", getshort());
			break;
		case OPPROC:
			printf(" $%d",getshort());
			break;
		case OPINSTRLAB:
			printf(" *%d",getshort());
			break;
		case OPOFFSET:
			printf(" %ld", getoff());
			break;
		case OPLIST:
			arglist();
			break;
	}
	printf("\n");
	return TRUE;
}


showl()
{
	while (showinstr());
}



arglist()
{
	short length;
	for (;;) {
		switch((short) getbyte()) {
			case ARGOBJECT:
				printf(" %d", getshort());
				break;
			case ARGPROC:
				printf(" $%d",getshort());
				break;
			case ARGINSTRLAB:
				printf(" *%d",getshort());
				break;
			case ARGOFF:
				printf(" %ld", getoff());
				break;
			case ARGICN:
			case ARGUCN:
			case ARGFCN:
				printf(" %d",getshort());
				/* Fall through !! */
			case ARGSTRING:
				length = getshort();
				putchar(' ');
				putchar('"');
				while (length--) {
					putchar(getbyte());
				}
				putchar('"');
				break;
			case ARGCEND:
				return;
		}
	}
}



showlset()
{
	register short x;

	printf("{ ");
	while (x = getshort()) {
		printf("%d ",x);
	}
	printf("}\n");
}




showb()
{
	/* basic block file */

	short n,m;

	while (TRUE) {
		n = getshort();
		if (feof(f)) break;
		if (n == 0) {
			printf("Declaration Unit:\n");
			printf(dformat,"#instrs =",getshort());
			printf("\n");
			continue;
		}
		printf("Control Flow Graph:\n");
		printf("number of basic blocks: %d\n",n);
		m = getshort(); /* #loops */
		while (n--) {
			printf("	BASIC BLOCK\n");
			printf(dformat,"id =",getshort());
			printf(dformat,"# instrs =",getshort());
			printf("		succ =");
			showlset();
			printf("		pred =");
			showlset();
			printf(dformat,"idom =",getshort());
			printf("		loops =");
			showlset();
			printf(dformat,"flags =",getshort());
		}
		printf("number of loops: %d\n",m);
		while (m--) {
			printf("	LOOP\n");
			printf(dformat,"id =",getshort());
			printf(dformat,"level =",getshort());
			printf(dformat,"entry =",getshort());
			printf(dformat,"end =",getshort());
		}
		printf("\n");
	}
}


showc()
{
	int n,m,cnt,t;

	cnt = 1;
	while(TRUE) {
		t = getshort();
		if (feof(f)) break;
		printf("CALL %d\n",cnt++);
		printf(format,"nestlevel =",t);
		printf(format,"calling p. =",getshort());
		printf(format,"call_id =",getshort());
		printf(format,"called p. =",getshort());
		printf(format,"looplevel =",getbyte());
		printf(format,"flags =",getbyte());
		printf(format,"ratio =",getshort());
		printf("	actuals:");
		n = getshort();
		if (n == 0) {
			printf("  ---\n");
		} else {
			while (n--) {
				printf("\n");
				m = getshort();
				printf(oformat,"size =",getoff());
				printf(dformat,"inl =",getbyte());
				while (m--) {
					printf("		");
					showinstr();
				}
			}
		}
	}
}
