#include <u.h>
#include <libc.h>
#include <stdio.h>
#include "dat.h"
#include "fns.h"
#include "y.tab.h"
#include "op.h"
#define LEQ 3
#define INSWT 4
#define CARRY 5
#define LTN 6
#define NULLARGS (void *) 0, (void *) 0 
#define RETONE(mt) {(mt)->care = 0; (mt)->true = 0; return((mt) + (flip ? 0 : 1) );}
#define RETZERO(mt) {(mt)->care = 0; (mt)->true = 0; return((mt) + (flip ? 1 : 0) );}

Minterm* caseneg(int, unsigned int, Node *, Node *, Minterm *);
Minterm* varls(int, unsigned int, Node *, Node *, Minterm *);
Minterm* varrs(int, unsigned int, Node *, Node *, Minterm *);
Minterm* caseinswt(int, unsigned int, Node * , Node* , Minterm *, int *, Node **);
Minterm* caseswitch(int , unsigned int , Node * , Node * , Minterm *);
Minterm* casesub(int , unsigned int , Node * , Node * , Minterm *);
Minterm* casexor(int , unsigned int , Node * , Node * , Minterm *);
Minterm* caselt(int , unsigned int , Node * , Node * , Minterm *);
Minterm* caseadd(int , unsigned int , Node * , Node * , Minterm *);
Minterm* casecarry(int , unsigned int , Node * , Node * , Minterm *);
Minterm* caseeq( int , Node * , Node * , Minterm *);
Minterm* and(int, Minterm *, Minterm *, Minterm *);
Minterm* logic(int, Node *, Minterm *);
void qsort(void *base, long nel, long width, int (*compar)(void*, void*));
int min_sort(Minterm * dest, Minterm *start, int count);



int
min_min(Minterm *m0, Minterm *m1, Minterm * m2) 
{

/* special case return -1 if have xn & !xn */
	if(m1->care & m2->care
			& (m1->true ^ m2->true)) {
		return (-1);
	}

	m0->care = (m1->care | m2->care);
	m0->true = (m1->true & m1->care) | (m2->true & m2->care);
	return (0);
}

#define TWARGS flip, bit, code, left, right, mt

Minterm*
tree_walk(int flip, unsigned int bit, int code, Node * left, Node * right, int Czero, int Cone, Minterm * mt, void * arg0, void * arg1) 
{
	Hshtab * hp;
	unsigned int lo;
	int i;
	Minterm *mt0 , *mt1, *mt2;
	Node *tp0;
if(yydebug) {
	fprintf(stderr, "tree_walk %d %x %s %x %x %x %x %x\n", flip, bit, getop(code), left, right, Czero, Cone, mt);
	fflush(stderr);
}
	if(Cone & bit) RETONE(mt)
	else if(Czero & bit)  RETZERO(mt)
	switch(code) {

   case ASSIGN:
	while((right->code == ASSIGN) || (right->code == DONTCARE))
		right = right->t2;
	return(tree_walk(flip, bit, right->code, right->t1, right->t2, right->Czero, right->Cone, mt, NULLARGS));

   case OR:

	mt1 = tree_walk(flip, bit, left->code, left->t1, left->t2, left->Czero, left->Cone, mt, arg0, arg1);
	if((flip == 0) && ((mt1 - mt) == 1) && (mt->care == 0)) return(mt1);
	if(flip && (mt1 == mt)) return(mt1);
	mt2 = tree_walk(flip, bit, right->code, right->t1, right->t2, right->Czero, right->Cone, mt1, arg0, arg1);
	return(and(flip?0:1, mt, mt1, mt2));

   case AND:

	mt1 = tree_walk(flip, bit, left->code, left->t1, left->t2, left->Czero, left->Cone, mt, NULLARGS);
	if((flip == 0) && (mt1 == mt)) return(mt1);
	if(flip && ((mt1 - mt) == 1) && (mt->care == 0)) return(mt1);
	mt2 = tree_walk(flip, bit, right->code, right->t1, right->t2, right->Czero, right->Cone, mt1, NULLARGS);
	return(and(flip, mt, mt1, mt2));


   case COM:
	return(tree_walk(flip?0:1, bit, left->code, left->t1, left->t2, left->Czero, left->Cone, mt, NULLARGS));

   case NEG:
	return(caseneg(flip, bit, left, right, mt));

   case FIELD:
	lo = LO((Hshtab *) left);
	while(bit != 1) { bit >>= 1; lo += 1; }
	if(lo >= HI((Hshtab *) left))
		RETZERO(mt);
	mt->care = finddepend(fields[lo]);
	mt->true = flip ? 0 : mt->care;
	return(mt+1);

   case BOTH:
   case INPUT:
	if(bit != 1)  RETZERO(mt);
	hp = (Hshtab *) left;
	mt->care = finddepend(hp);
	mt->true = flip ? 0 : mt->care;
	return(mt+1);

   case NUMBER:
	if((((Value) left) & bit) ? !flip : flip ) {
		mt->care = 0;
		mt->true = 0;
		mt0 = (mt+1);
	}
	else mt0 = mt;
if(yydebug) {
	fprintf(stderr,"number: %d\n", left);
	printmt(mt, mt0);
}
	return(mt0);

   case RS:
	if(!vconst(right))
		return(varrs(flip, bit, left, right, mt));
	bit <<= eval(right);
	if(!bit) RETZERO(mt);
	return(tree_walk(flip, bit, left->code, left->t1, left->t2,  left->Czero, left->Cone,mt, NULLARGS));

   case LS:
	if(!vconst(right))
		return(varls(flip, bit, left, right, mt));
	bit >>= eval(right);
	if(!bit) RETZERO(mt);
	return(tree_walk(flip, bit, left->code, left->t1, left->t2,  left->Czero, left->Cone,mt, NULLARGS));
	
   case NE:
   case EQ:
	if(bit != 1) {
		if(flip) {
			mt->care = 0;
			mt->true = 0;
			return(mt+1);
		}
		return(mt);
	}
	if(code == NE) flip = flip ? 0 : 1;
   case LEQ:
	return(caseeq(flip, left, right, mt));


   case EQN:
	tp0 = ((Hshtab *) left)->assign;
	return(tree_walk(flip, bit, tp0->code, tp0->t1, tp0->t2, tp0->Czero, tp0->Cone, mt, NULLARGS));


   case LE:
   case GE:
   case GT:
   case LT:
	if(bit != 1) {
		if(flip) {
			mt->care = 0;
			mt->true = 0;
			return(mt+1);
		}
		return(mt);
	}
	if((code == GT) || (code == LE)) {
		tp0 = left;
		left = right;
		right = tp0;
	}
	if((code == GE) || (code == LE))
		flip = flip?0:1;
	for(i = 0x80000000; i != 0; i = ((unsigned int) i) >> 1) {
		if(!(left->Cone & right->Cone & i)
		 && !(left->Czero & right->Czero & i)) break;
	}
	return(caselt(flip, i<<1, left, right, mt));


   case LTN:
	return(caselt(flip, bit, left, right, mt));

   case NOT:
	if(bit != 1) {
		if(flip) {
			mt->care = 0;
			mt->true = 0;
			return(mt+1);
		}
		return(mt);
	}
	return(logic(flip?0:1, left, mt));

   case LOR:
   case LAND:
	if(bit != 1) {
		if(flip) {
			mt->care = 0;
			mt->true = 0;
			return(mt+1);
		}
		return(mt);
	}
	mt0 = logic(flip, left, mt);
	mt1 = logic(flip, right, mt0);
	if(code == LOR) flip = flip?0:1;
	return(and(flip, mt, mt0, mt1));

   case XOR:
	return(casexor(flip, bit, left, right, mt)); 
	
   case CND:
	mt0 = logic(flip, left, mt);
	tp0 = right->t1;
	mt1 = tree_walk(flip, bit, tp0->code, tp0->t1, tp0->t2, tp0->Czero, tp0->Cone, mt0, NULLARGS);
	mt0 = and(flip, mt, mt0, mt1);
	mt1 = logic(flip?0:1, left, mt0);
	tp0 = right->t2;
	mt2 = tree_walk(flip, bit, tp0->code, tp0->t1, tp0->t2, tp0->Czero,tp0->Cone, mt1, NULLARGS);
	mt1 = and(flip, mt0, mt1, mt2);
	mt1 = and(flip?0:1, mt, mt0, mt1);
	return(mt1);
   case SUB:
	return(casesub(flip, bit, left, right, mt));

   case ADD:
	return(caseadd(flip, bit, left, right, mt));

   case CARRY:
	return(casecarry(flip, bit, left, right, mt));

   case SWITCH:
	return(caseswitch(flip, bit, left, right, mt));

   case INSWT:
	return(caseinswt(flip, bit, left, right, mt, (int *) arg0, (Node **) arg1));

   default:
	fprintf(stderr, "unknown code %d\n", code);
	exits("error");;

	}
	return((Minterm * ) 0 );
}


Minterm*
varrs(int flip, unsigned int bit, Node *left, Node *right, Minterm *mt0)
{

	Node t0, t1, t2;
	Minterm *mt1, *mt2;
	int i;
	t0.Czero = t0.Cone = t1.Czero = t1.Cone = 0;
	t2.Czero = t2.Cone = 0;
	mt1 = mt0;
	for(i = 0; bit; bit <<=1, ++i) {
		t0.code = NUMBER;
		t0.t1 = (Node *) i;
		t1.code = LEQ;
		t1.t1 = right;
		t1.t2 = &t0;
		t2.code = AND;
		t2.t1 = &t1;
		t2.t2 = left;
		mt2 = tree_walk(flip, bit, AND, &t1, &t2, 0, 0, mt1, NULLARGS);
		mt1 = and(flip?0:1, mt0, mt1, mt2);
if(yydebug){
	fprintf(stderr, "ls: bit %x\n", bit); printmt(mt0, mt1);}
	}
	return(mt1);
}

Minterm*
caseneg(int flip,  unsigned int bit, Node *left, Node *right, Minterm *mt)
{
	Node t0;

	USED(right);
	t0.code  = NUMBER;
	t0.t1 = (Node *) 0;
	t0.Czero = ~1;
	t0.Cone = 1;
	return(tree_walk(flip, bit, SUB, &t0, left, 0, 0, mt, NULLARGS));
}	




Minterm*
varls(int flip, unsigned int bit, Node *left, Node *right, Minterm *mt0)
{

	Node t0, t1, t2;
	Minterm *mt1, *mt2;
	int i;
	t0.Czero = t0.Cone = t1.Czero = t1.Cone = 0;
	t2.Czero = t2.Cone = 0;
	mt1 = mt0;
	for(i = 0; bit; bit >>=1, ++i) {
		t0.code = NUMBER;
		t0.t1 = (Node *) i;
		t1.code = LEQ;
		t1.t1 = right;
		t1.t2 = &t0;
		t2.code = AND;
		t2.t1 = &t1;
		t2.t2 = left;
		mt2 = tree_walk(flip, bit, AND, &t1, &t2, 0, 0, mt1, NULLARGS);
		mt1 = and(flip?0:1, mt0, mt1, mt2);
if(yydebug) {
	fprintf(stderr, "ls: bit %x\n", bit); printmt(mt0, mt1);}
	}
	return(mt1);
}
/*
Minterm* 
casemul(int flip, unsigned int bit, Node * left, Node* right, Minterm *mt, NULLARGS)
{
	Node t0, t1;
	t0.Czero = t0.Cone = t1.Czero = t1.Cone = 0;
	if(bit < (1 << shift) RETZERO(mt);
	t1.code = LS;
	t1.t2 = shift;
	t1.t1 = left;
	t0.code = AND;
	t0.
	t2.code = IMUL;
	t2.t1 = left;
	t2.t2 = right;
	mt0 = tree_walk(flip, bit, ADD, &t0, &t1, mt, lastcasep, defltp);
if(yydebug) {
	fprintf(stderr, "lt: bit %x\n", bit); printmt(mt, mt0);
}
*/

Minterm*
caseswitch(int flip, unsigned int bit, Node * left, Node* right, Minterm *mt)
{
	int lastcase;
	Minterm* mt0;
	Node * deflt;
	deflt = (Node * ) 0;
	lastcase = -1;
	mt0 = tree_walk(flip, bit, INSWT, left, right, 0, 0, mt, &lastcase, &deflt);
if(yydebug) {
	fprintf(stderr, "caseswitch: bit %x\n", bit); printmt(mt, mt0);
}
	return(mt0);
}

Minterm*
caseinswt(int flip, unsigned int bit, Node * left, Node* right, Minterm *mt, int *lastcasep, Node **defltp)
{
	Node *tp, t0, t1, t2, t3, t4, t5;
	Minterm* mt0;
	t0.Czero = t0.Cone = t1.Czero = t1.Cone = 0;
	t2.Czero = t2.Cone = t3.Czero = t3.Cone = 0;
	t4.Czero = t4.Cone = t5.Czero = t5.Cone = 0;
	tp = right;
	if(tp == (Node *) 0) {
		if(flip) {
			mt->care = 0;
			mt->true = 0;
			return(mt+1);
		}
		return(mt);
	}
	if (tp->code == ALT) {
		if(tp->t1 == (Node *) 0) {
			if((*defltp)) {
				fprintf(stderr, "switch has 2 deflts\n");
				exits("error");;
			}
			tp = tp->t2;
			if(tp->code != CASE) {
				fprintf(stderr, "switch scrogged\n");
				exits("error");;
			}
			*defltp = tp->t1;
			mt0 =
				tree_walk(flip, bit, INSWT,
					left, tp->t2, 0, 0, mt, lastcasep, defltp);
if(yydebug) {
	fprintf(stderr, "lt: bit %x\n", bit); printmt(mt, mt0);
}
			return(mt0);
		}
		if(!vconst(tp->t1)) {	
			fprintf(stderr, "switch case not constant\n");
			exits("error");;
		}
		*lastcasep = eval(tp->t1) - 1;
		tp = tp->t2;
	}
	if(tp->code != CASE) {
		fprintf(stderr, "switch scrogged\n");
		exits("error");;
	}
	t0.code = NUMBER;
	t0.t1 = (Node *) ++(*lastcasep);
	t1.code = LEQ;
	t1.t1 = left;
	t1.t2 = &t0;
	t2.code = AND;
	t2.t1 = &t1;
	t2.t2 = tp->t1;
	t3.code = INSWT;
	t3.t1 = left;
	t3.t2 = tp->t2;
	mt0 = tree_walk(flip, bit, OR, &t2, &t3, 0, 0, mt, lastcasep, defltp);
if(yydebug) {
	fprintf(stderr, "lt: bit %x\n", bit); printmt(mt, mt0);
}
	return(mt0);
}
	
	
	
		
		


	
Minterm*
casesub(int flip, unsigned int bit, Node * left, Node* right, Minterm *mt)
{
	Node t0, t1, t2, t3, t4, t5;
	Minterm* mt0;
	t0.Czero = t0.Cone = t1.Czero = t1.Cone = 0;
	t2.Czero = t2.Cone = t3.Czero = t3.Cone = 0;
	t4.Czero = t4.Cone = t5.Czero = t5.Cone = 0;
	t0.code = ADD;
	t0.t1 = &t1;
	t0.t2 = &t2;
	t1.code = NUMBER;
	t1.t1 = (Node *) 1;
	t2.code = COM;
	t2.t1 = right;
	mt0 = tree_walk(flip, bit, ADD, left, &t0, 0, 0, mt, NULLARGS);
if(yydebug) {
	fprintf(stderr, "lt: bit %x\n", bit); printmt(mt, mt0);
}
	return(mt0);
}


Minterm*
caselt(int flip, unsigned int bit, Node * left, Node* right, Minterm *mt)
{
	Node t0, t1, t2, t3, t4, t5;
	Minterm* mt0;
	t0.Czero = t0.Cone = t1.Czero = t1.Cone = 0;
	t2.Czero = t2.Cone = t3.Czero = t3.Cone = 0;
	t4.Czero = t4.Cone = t5.Czero = t5.Cone = 0;
	if(bit == 1) {
		if(flip) {
			mt->care = 0;
			mt->true = 0;
			mt0 = mt+1;
		}
		else mt0 = mt;
	}
	else {
		if(bit == 0) bit = 0x80000000;
		else bit >>= 1;
		t0.code = AND;
		t0.t1 = &t1;
		t0.t2 = right;
		t1.code = COM;
		t1.t1 = left;
		t1.t2 = (Node *) 0;
		t2.code = AND;
		t2.t1 = &t3;
		t2.t2 = &t4;
		t3.code = COM;
		t3.t1 = &t5;         /*          LT  RT             */
		t3.t2 = (Node *) 0;  /*            XOR              */
		t4.code = LTN;       /*    LT NUL   5 NUL LT RT     */
		t4.t1 = left;        /*     COM      COM   LTN      */
		t4.t2 = right;       /*      1   RT   3     4       */
		t5.code = XOR;       /*        AND      AND         */
		t5.t1 = left;        /*         0        2          */
		t5.t2 = right;       /*            OR               */
		mt0 = tree_walk(flip, bit, OR, &t0, &t2, 0, 0, mt, NULLARGS);
	}
if(yydebug) {
	fprintf(stderr, "lt: bit %x\n", bit); printmt(mt, mt0); fflush(stderr);
}
	return(mt0);
}


Minterm*
casecarry(int flip, unsigned int bit, Node * left, Node* right, Minterm *mt)
{
	Node t0, t1, t2, t3;
	Minterm* mt0;
	t0.Czero = t0.Cone = t1.Czero = t1.Cone = 0;
	t2.Czero = t2.Cone = t3.Czero = t3.Cone = 0;
	if(bit != 1) {
		mt0 = tree_walk(flip, bit>>1, left->code, left->t1, left->t2, left->Czero, left->Cone, mt, NULLARGS);
		if(mt0 == mt) {
			mt0 = tree_walk(flip, bit>>1, right->code, right->t1, right->t2, right->Czero, right->Cone, mt, NULLARGS);
			if(mt0 == mt) bit = 1;
		}
	} 
	if(bit == 1) {
		if(flip) {
			mt->care = 0;
			mt->true = 0;
			mt0 = mt+1;
		}
		else mt0 = mt;
	}
	else {
		bit >>= 1;
		t0.code = AND;
		t0.t1 = left;
		t0.t2 = right; 
		t1.code = CARRY;
		t1.t1 = left;
		t1.t2 = right;
		t2.code = OR;            /*          L R    L R   */
		t2.t1 = left;            /*    L R    C      |    */
		t2.t2 = right;           /*     *         *       */
		t3.code = AND;           /*           |           */
		t3.t1 = &t1;
		t3.t2 = &t2;
		mt0 = tree_walk(flip, bit, OR, &t0, &t3, 0, 0, mt, NULLARGS);
	}
if(yydebug) {
	fprintf(stderr, "carry: bit %x\n", bit); printmt(mt, mt0);
}
	return(mt0);
}


Minterm*
caseadd(int flip, unsigned int bit, Node * left, Node* right, Minterm *mt)
{
	Node t1, t2;
	Minterm *mt0;
	t2.Czero = t2.Cone = t1.Czero = t1.Cone = 0;
	t1.code = CARRY;
	t1.t1 = left;
	t1.t2 = right;
	t2.code = XOR;
	t2.t1 = left;
	t2.t2 = right;
	mt0 = tree_walk(flip, bit, XOR, &t1, &t2, 0, 0, mt, NULLARGS);
if(yydebug) {	fprintf(stderr, "add: bit %x\n", bit); printmt(mt, mt0);}
	return(mt0);
}

Minterm*
logic(int flip, Node *tp, Minterm *mt)
{
	unsigned int i;
	Minterm *mt0, *mt1;
	mt0 = tree_walk(flip, 1, tp->code,  tp->t1, tp->t2, 0, 0, mt, NULLARGS); 
	for(i = 2 ; i; i <<= 1) {
		mt1 = tree_walk(flip, i, tp->code,  tp->t1, tp->t2, 0, 0, mt0, NULLARGS); 
		mt0 = and(flip?0:1, mt, mt0, mt1);
	}
	return(mt0);
}

Minterm*
caseeq(int flip, Node * left, Node * right, Minterm *mt)
{
	Minterm *mt0, *mt1;
	unsigned int i;
	if(flip == 0) {
		mt->care = 0;
		mt->true = 0;
		mt0 = mt + 1;
	}
	else 
		mt0 = mt;
	for(i = 1; i; i <<= 1) {
		mt1 = casexor(flip?0:1, i, left, right, mt0);
		mt0 = and(flip, mt, mt0, mt1);
	}
	return(mt0);
}
		
Minterm*
casexor(int flip, unsigned int bit, Node * left, Node * right, Minterm *mt)
{
	Node t1, t2, t3, t4;     
	Minterm *mt0;
	t1.Czero = t1.Cone = t2.Czero = t2.Cone = 0;
	t3.Czero = t3.Cone = t4.Czero = t4.Cone = 0;
	t1.code = t2.code = AND;
	t1.t1 = left;
	t1.t2 = &t3;
	t3.code = COM;
	t3.t1 = right;
	t2.t1 = &t4;
	t2.t2 = right;
	t4.code = COM;
	t4.t1 = left;
	mt0 = tree_walk(flip, bit, OR, &t1, &t2, 0, 0, mt, NULLARGS);
if(yydebug) {	fprintf(stderr, "xor: bit %x\n", bit); printmt(mt, mt0);}
	return(mt0);
}

Minterm*
and(int flip, Minterm * mt0, Minterm * mt1, Minterm * mt2) 
{
	int n;
	Minterm *m0, *m1, *m2;
	if(flip == 0) {
		for(m0 = mt0, m2 = mt2; m0 < mt1; ++m0)
			for(m1 = mt1; m1 < mt2; ++m1)
				if(min_min(m2, m0, m1) >= 0) ++m2;
		n = min_sort(mt0, mt2, m2-mt2);
	}
	else
		n = min_sort(mt0, mt0, mt2-mt0);
if(yydebug) {fprintf(stderr, "and: "); printmt(mt0, mt0+n);}
	return(mt0+n);
}

#ifdef PLAN9
int
min_cmp(Minterm * m1, Minterm *m2)
#endif
#ifndef PLAN9
int
min_cmp(void * mm1, void *mm2)
#endif
{
#ifndef PLAN9
	Minterm *m1, *m2;
	m1 = (Minterm *) mm1;
	m2 = (Minterm *) mm2;
#endif
	if(m1->care > m2->care) return(1);
	if(m1->care < m2->care) return(-1);
	if(m1->true > m2->true) return(1);
	if(m1->true < m2->true) return(-1);
	return(0);
}

int
min_cov(Minterm * dest, Minterm *start, int count)
{
	Minterm *mt0, *mt1, *mt2;
	int n, care0, care1, true0, true1;
	mt2 = start + count;
	care1 = 0;
	for(mt0 = start; mt0 < mt2; ++mt0) {
		care0 = mt0->care;
		true0 = mt0->true & care0;
		if((care0 == 0) && (true0 == (~0 & care1))) continue;
		for(mt1 = start; mt1 < mt2; ++mt1) {
			if(mt1 == mt0) continue;
			care1 = mt1->care;
			true1 = mt1->true & care1;
			if((care1 == 0) && (true1 == (~0 & care1))) continue;
			if((care1 == care0) && (true0 == true1)) {
				mt1->care = 0;
				mt1->true = ~0;
				continue;
			}
			n = care1 & care0;
			if((n & (true0 ^ true1)) != 0 ) continue;
			if(care1 & ~care0) continue;
			mt0->care = 0;
			mt0->true = ~0;
		}
	}
	for(mt0 = start, mt1 = dest; mt0 < mt2; ++mt0) {
		if(mt0->care == 0) {
			if(mt0->true == ~0) continue;
			if(mt0->true == 0) {
				dest->care = 0;
				dest->true = 0;
				return(1);
			}
		}
		*mt1++ = *mt0;
	}
	return(mt1-dest);
}

int
min_join(Minterm *start, int count)
{
	Minterm *mt0, *mt1, *mt2, *mt3;
	unsigned int n, care0, care1, true0, true1;
	if(count < 2) return(count);
	if((start->care == 0) && (start->true == 0))  return(1);
	mt3 = mt2 = start + count;
	for(mt0 = start; mt0 < mt2; ++mt0) {
		care0 = mt0->care;
		true0 = mt0->true & care0;
		for(mt1 = mt0+1; mt1 < mt2; ++mt1) {
			care1 = mt1->care;
			true1 = mt1->true & care1;
			if(care1 != care0) continue;
			if((care1 == 0) && true1 == 0) {
				start->care = 0;
				start->true = 0;
				return(1);
			}
			n = (true1 ^ true0);
			n = ~n ^ -((int) n);
			n = n ^ n >> 1;
			if(n != (true1 ^ true0)) continue;
			mt3->care = care0 & ~n;
			mt3->true = true0 & ~n;
			if(mt3 == &minterms[NCOMP-1]) {
fprintf(stderr, "%x/%x %x/%x %x %x %x %x\n", care0, true0, care1, true1, (true1 ^ true0),
~(true1 ^ true0), -((int) (true1 ^ true0)), -1 >> 1, n);
printmt(start, mt3);
				fprintf(stderr, "out of minterms");
				exits("error");;
			}
			++mt3;
		}
		mt2 = mt3;
	}
	return(mt3-start);
}
extern int REDUCE;
			
int
min_sort(Minterm * dest, Minterm *start, int count)
{
	Minterm * mt,*m1;
	int n;
	if(count == 0) return(0);
	if(REDUCE == 0) {
		qsort(start, count, sizeof(Minterm), min_cmp);
		m1= start + count;
		if((start->care == 0) && (start->true == 0)) {
			dest->care = 0;
			dest->true = 0;
			return(1);
		}
		for(mt = start,n = 0; mt < m1; ++mt) {
			*dest++ = *mt;
			++n;
			while(min_cmp(mt, (mt+1)) == 0)
				if(++mt >= m1-1) break;
			
		} 
	}
	else {
		n = min_join(start, count);
		n = min_cov(dest, start, n);
	}
	return(n);
}
	
int
vconst(Node *tp)
{

	switch(tp->code) {
	default:
		return 0;
	case LAND:
	case LOR:
	case AND:
	case OR:
	case XOR:
	case ADD:
	case SUB:
	case MUL:
	case DIV:
	case MOD:
	case LT:
	case GT:
	case EQ:
	case NE:
	case GE:
	case LE:
	case LS:
	case RS:
		if(!vconst(tp->t1))
			return 0;
		if(!vconst(tp->t2))
			return 0;
		return 1;
	case FLONE:
	case FRONE:
	case GREY:
	case NEG:
	case NOT:
	case COM:
		if(!vconst(tp->t1))
			return 0;
		return 1;
	case CND:
		if(!vconst(tp->t1))
			return 0;
		if(eval(tp->t1)) {
			if(!vconst(tp->t2->t1))
				return 0;
			return 1;
		}
		if(!vconst(tp->t2->t2))
			return 0;
		return 1;
	case NUMBER:
		return 1;
	}
}
