Esempio n. 1
0
/* i_igspill: spill node i, removing it from index j in interference graph g */
static void i_igspill (i_local_t i, i_local_t j, ig_t g) {
     SCLASS(i) = STACK;		/* Update storage location */
     if (TYPE(i) == I_B)
	  ADDR(i) = v_localb(ADDR(i));
     else ADDR(i) = v_local(TYPE(i));
     i_igremove(j, g);		/* Remove node i from integer IG */
}
Esempio n. 2
0
/*
 * Find a leaf type node that puts the value into a register.
 */
int
findleaf(NODE *p, int cookie)
{
	extern int *qtable[];
	struct optab *q = NULL; /* XXX gcc */
	int i, sh;
	int *ixp;

	F2DEBUG(("findleaf p %p (%s)\n", p, prcook(cookie)));
	F2WALK(p);

	ixp = qtable[p->n_op];
	for (i = 0; ixp[i] >= 0; i++) {
		q = &table[ixp[i]];

		F2DEBUG(("findleaf: ixp %d\n", ixp[i]));
		if (!acceptable(q))		/* target-dependent filter */
			continue;
		if ((q->visit & cookie) == 0)
			continue; /* wrong registers */

		if (ttype(p->n_type, q->rtype) == 0 ||
		    ttype(p->n_type, q->ltype) == 0)
			continue; /* Types must be correct */

		F2DEBUG(("findleaf got types, rshape %s\n", prcook(q->rshape)));

		if (chcheck(p, q->rshape, 0) != SRDIR)
			continue;

		if (q->needs & REWRITE)
			break;	/* Done here */

		break;
	}
	if (ixp[i] < 0) {
		F2DEBUG(("findleaf failed\n"));
		if (setuni(p, cookie))
			return FRETRY;
		return FFAIL;
	}
	F2DEBUG(("findleaf entry %d\n", ixp[i]));

	sh = ffs(cookie & q->visit & INREGS)-1;
	F2DEBUG(("findleaf: node %p (%s)\n", p, prcook(1 << sh)));
	p->n_su = MKIDX(ixp[i], 0);
	SCLASS(p->n_su, sh);
	return sh;
}
Esempio n. 3
0
File: cfg.c Progetto: berkus/lang-e
void i_fg_build (void) {
     unsigned i;
     i_puint32 cp = i_buf;	/* Start of code to analyze */
     i_puint32 lp = i_lim;	/* End of code to analyze */
     i_uint32 op;		/* Current opcode */
     i_bb_t b;			/* Current basic block */

     num_bb = 0;
     b = bb_alloc();
     b->h = cp;

     if (i_ralloctype == RA_EZ) {
	  i_fg_root = i_fg_tail = b;
	  b->t = lp - i_isize;
	  return;
     }

     i_calls_cur = i_calls_lim = 0;
     NEW0(lbl2bb, i_lab_cur); 
     NEW(fwdrefs, i_nbb); fwdref_cur = 0;

     i_fg_root = b;
     do {
	  assert(b && !b->init);
	  op = get_op(cp);
	  switch(i_op2class[op]) {
	  case I_BOP:	  case I_BOPF:
	  case I_MOPR:	  case I_MOPRF:
	       assert(!isimmed(op));
	       markuse(b, get_rs(cp));
	       markuse(b, get_rs2(cp));
	       markdef(b, get_rd(cp));
	       break;
	  case I_BOPI:	  case I_MOPRI:	case I_MOPRIF:
	       assert(isimmed(op));
	       markuse(b, get_rs(cp));
	       markdef(b, get_rd(cp));
	       break;
	  case I_MOPW:	  case I_MOPWF:
	       assert(!isimmed(op));
	       markuse(b, get_rd(cp));
	       markuse(b, get_rs(cp));
	       markuse(b, get_rs2(cp));
	       break;
	  case I_MOPWI:	  case I_MOPWIF:
	       assert(isimmed(op));
	       markuse(b, get_rd(cp));
	       markuse(b, get_rs(cp));
	       break;
	  case I_UOP:     case I_UOPF:
	       assert(!isimmed(op));
	       markuse(b, get_rs(cp));
	       markdef(b, get_rd(cp));
	       break;
	  case I_UOPI:
	       assert(isimmed(op));
	       markdef(b, get_rd(cp));
	       break;
	  case I_SET:	   case I_SETF:
	       markdef(b, get_rd(cp));
	       break;
	  case I_LEA:	   case I_LEAF:
	       SCLASS(get_rs(cp)) = STACK;
	       markuse(b, get_rs(cp));
	       markdef(b, get_rd(cp));
	       break;
	  case I_RET:	   case I_RETF:
	       if (op != i_op_retv)
		    markuse(b, get_rd(cp));
	  case I_RETI:
	       b = bb_finalize(b, cp, lp, i_isize, false);
	       break;
	  case I_BR:	  case I_BRF:
	       markuse(b, get_rs2(cp));
	  case I_BRI:
	       markuse(b, get_rs(cp));
	       bb_linklbl(b, get_rd(cp));
	       b = bb_finalize(b, cp, lp, i_isize, true);
	       break;
	  case I_CALL:	  case I_CALLF:
	       markuse(b, get_rs(cp));
	  case I_CALLI:	  case I_CALLIF:
	       if (op != i_op_callv && op != i_op_callvi)
		    markdef(b, get_rd(cp));
	       markcall(cp);
	       b = bb_finalize(b, cp, lp, 2*i_isize, true);
	       cp += i_isize;	/* Calls are 2x as long as other insns */
	       break;
	  case I_ARG:	  case I_ARGF:
	       markuse(b, get_rd(cp));
	       break;
	  case I_JMP:
	       assert(get_rd(cp) < num_i);
	       markuse(b, get_rd(cp));
	       b = bb_finalize(b, cp, lp, i_isize, false);
	       break;
	  case I_JMPI:
	       bb_linklbl(b, get_imm(cp));
	       b = bb_finalize(b, cp, lp, i_isize, false);
	       break;
	  case I_MISC:
	       switch (op) {
	       case i_op_lbl:
		    if (cp > b->h) /* If not at head of current block ... */
				/* ... make this the head of a new block */
			 b = bb_finalize(b, cp-i_isize, lp, i_isize, true);
		    lbl2bb[get_rd(cp)] = b;
		    break;
	       default:		/* refmul, refdiv, self, nop */
		    break;
	       }
	       break;
	  default:
	       assert(0);
	  }
     } while ((cp += i_isize) < lp);
     i_fg_tail = b;
     for (i = 0; i < fwdref_cur; i++)
	  bb_linkbb(fwdrefs[i].src, lbl2bb[fwdrefs[i].dst]);
#ifndef NDEBUG
     for (i = 0, b = i_fg_root; b; b = b->lnext) i++;
     assert(i == num_bb);
#endif
}
Esempio n. 4
0
/* i_ig_color: color the interference graph g for storage class (INT/FP) sc */
void i_ig_color (int sc) {
     ig_t g, g2;		/* Backup of interference graph */

     i_local_t *nstk;		/* Node stack: when removing a node from IG,
				   push it onto this stack */
     unsigned int ncnt = 0;	/* Counter for node stack */

     unsigned int nnodes;	/* No. of nodes left in IG when coloring */
     unsigned int nremoved;	/* No. of nodes removed in 1 coloring pass */

     i_local_t i, j;		/* Dummy variable indices / counters */
     unsigned int k;
     unsigned int reg;		/* Temporary color variable */

     unsigned int ncolors;	/* Number of available registers */

				/* Data for prioritized spilling */
     i_ref_t threshref = 0.;	/* Threshold refcnt (see below) */
     i_local_t *deferspill = 0;	/* Maintains info of which spills have been 
				   deferred */
     i_local_t Vnum, Vbase;	/* Number of vars of sclass sc, and their
				   base offset in i_locals */
#ifndef NDEBUG
     int dcnt = 0;
#endif

     if (sc == FP) {
	  g = fig; Vnum = num_f; Vbase = i_loc_ilim;
     } else {
	  g = iig; Vnum = num_i; Vbase = 0;
     }
     ncolors = i_reg_navail(sc);/* Find number of available registers */

     NEW(nstk, Vnum);		/* Allocate register stack */
     g2 = i_igcopy(g);		/* Make backup copy of IG */

     NEW0(removed, Vnum);	/* Mark whether a node has been removed */

     DEBUG(i_igunparse(g));

     if (i_dorefcnt) {		/* Find maxref */
	  i_ref_t t = 0.;
	  unsigned n = 0;
	  NEW0(deferspill, Vnum);
	  for (i = 0; i < Vnum; i++) {
	       j = i + Vbase;	/* Get real index of this variable */
	       if (! (PARAMP(j) || SCLASS(j) == STACK)) {
		    t += REFCNT(j); n++;
	       }
	  }
	  threshref = t/(n*2);	/* For any clique (V,E) where |V| > # regs,
				   spill first all v with refcnt < threshref;
				   this is a little bogus (the right way would
				   be to sort the v \in V and spill in order
				   of increasing refcnt), but fast, and it
				   works pretty well. */
     }
				/* 
				 * Dismantle interference graph
				 */
     do {
	  nremoved = 0;		/* Reset number of nodes removed */
	  nnodes = 0;		/* And number of nodes remaining */
				/* Loop over all variables (ie. nodes in IG) */
	  for (i = 0; i < Vnum; i++) {
	       if (removed[i])
		    continue;
	       j = i + Vbase;	
				/* Skip params: already allocated */
	       if (PARAMP(j)) {
		    i_igremove(i, g);
		    continue;
	       }
				/* Remove non-register candidates */
	       if (SCLASS(j) == STACK) {
		    i_igspill(j, i, g);
		    continue;
	       }
				/* Find valence of node i */
	       k = bv_num(row(i, g));
	       if (k == 0) {
		    removed[i] = 1;
		    continue;
	       }
	       if (k <= ncolors) {
				/* Valence <= number of colors: can color.
				   Store index of node i for later use  */
		    push(i, nstk, ncnt);
				/* Remove node i from graph */
		    i_igremove(i, g);
		    ++nremoved;	/* Increase the counter of removed nodes */
	       } else
		    ++nnodes;	/* Can't color: increase number of nodes
				   left in graph */
	  }
     } while (nnodes > 0 && nremoved > 0);

     while (nnodes > 0) {	/* Try nodes with high valence/low refcount */
	  i_local_t target = i_zero;
	  unsigned int mc = 0;
#ifndef NDEBUG
	  if (i_debug) {
	       printf("Initial spill loop, #%d (nnodes=%d,dorefcnt=%d)\n", 
		      dcnt++, nnodes, i_dorefcnt);
	  }
#endif
	  for (i = 0; i < Vnum; i++) {
	       if (removed[i])
		    continue;
	       j = i + Vbase;
				/* Find valence of node i */
	       k = bv_num(row(i, g));
	       assert(k);
	       if (k <= ncolors) {
				/* Can color: evidently we removed some of 
				   this node's neighbors on a previous 
				   iteration of this inner loop */
				/* Store index of node i for later use */
		    push(i, nstk, ncnt);
				/* Remove node i from graph */
		    i_igremove(i, g);
		    --nnodes;	/* We have removed a node */
		    if (!nnodes)
			 break;
	       } else if (REFCNT(j) < 2*threshref && k > mc) {
		    mc = k;
		    target = i;
	       } 
	  }
	  if (nnodes)
	       if (target != i_zero) {
		    DEBUG(printf("Spilling(1) %d[n=%d,d=%d,k=%d,c=%f,t=%f]\n",\
				 target, nnodes, deferspill[target], mc, \
				 REFCNT(target+Vbase), threshref));
		    i_igspill(target+Vbase, target, g);
		    DEBUG(i_igunparse(g));
		    nnodes--;
	       } else {		/* Found nothing to spill here */
		    assert(target == i_zero);
		    break;
	       }
     }
     DEBUG(dcnt = 0);
     while (nnodes > 0) {	/* Final, aggressive spill loop */
#ifndef NDEBUG
	  if (i_debug) {
	       printf("Final spill loop, #%d (nnodes=%d)\n", dcnt++, nnodes);
	  }
#endif	  
	  for (i = 0; i < Vnum; i++) {
	       if (removed[i])
		    continue;
	       j = i + Vbase;
				/* Find valence of node i */
	       k = bv_num(row(i, g));
	       assert(k);
	       if (k <= ncolors) {
				/* Can color: evidently we removed some of 
				   this node's neighbors on a previous 
				   iteration of this inner loop */
				/* Store index of node i for later use */
			 push(i, nstk, ncnt);
				/* Remove node i from graph */
			 i_igremove(i, g);
	       } else if (!i_dorefcnt || deferspill[i] > 1 
			  || REFCNT(j) < 3*threshref) {
				/* Small refcnt or already deferred: spill. */
		    DEBUG(printf("Spilling(2) %d[n=%d,d=%d,k=%d,c=%f,t=%f]\n",\
				 i, nnodes, deferspill[i], k, \
				 REFCNT(j), threshref));
		    i_igspill(j, i, g);
		    DEBUG(i_igunparse(g));
	       } else {		/* This node is referenced a lot; try deferring
				   the spill. */
		    ++deferspill[i];
		    continue;	/* Do not remove this node, yet */
	       }
	       --nnodes;	/* We have removed a node */
	  }
     }
				/*
				 * Rebuild interference graph, coloring nodes
				 */
     while (ncnt) {
				/* Find a new node to add back to the IG */
	  pop(i, nstk, ncnt);
				/* Make unavailable the registers of all nodes
				   adjacent to node i in the IG */
	  bv_eachbit(row(i, g2), i_rmreg, (void *)Vbase);
	  reg = i_reg_get(sc);	/* Get an int register */
	  j = i + Vbase;
	  ADDR(j) = reg;
	  SCLASS(j) = REGISTER;	/* Set storage location info */
	  i_reg_mask(sc);	/* Reset the set of available registers */
     }
     i_reg_resetmask(sc);
}
Esempio n. 5
0
/* i_rmreg: make unavailable the registers of all nodes adjacent to node i */
static inline void i_rmreg (i_local_t i, bvt v, void *x) {
     i_local_t j = i + (i_local_t)x;
     if (SCLASS(j) == REGISTER && !PARAMP(j))
	  i_reg_use(i_ty2sc[TYPE(j)], ADDR(j));
}
Esempio n. 6
0
/*
 * Find a UNARY op that satisfy the needs.
 * For now, the destination is always a register.
 * Both source and dest types must match, but only source (left)
 * shape is of interest.
 */
int
finduni(NODE *p, int cookie)
{
	extern int *qtable[];
	struct optab *q;
	NODE *l, *r;
	int i, shl = 0, num = 4;
	int *ixp, idx = 0;
	int sh;

	F2DEBUG(("finduni tree: %s\n", prcook(cookie)));
	F2WALK(p);

	l = getlr(p, 'L');
	if (p->n_op == CALL || p->n_op == FORTCALL || p->n_op == STCALL)
		r = p;
	else
		r = getlr(p, 'R');
	ixp = qtable[p->n_op];
	for (i = 0; ixp[i] >= 0; i++) {
		q = &table[ixp[i]];

		F2DEBUG(("finduni: ixp %d\n", ixp[i]));
		if (!acceptable(q))		/* target-dependent filter */
			continue;

		if (ttype(l->n_type, q->ltype) == 0)
			continue; /* Type must be correct */

		F2DEBUG(("finduni got left type\n"));
		if (ttype(r->n_type, q->rtype) == 0)
			continue; /* Type must be correct */

		F2DEBUG(("finduni got types\n"));
		if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE)
			continue;

		F2DEBUG(("finduni got shapes %d\n", shl));

		if ((cookie & q->visit) == 0)	/* check correct return value */
			continue;		/* XXX - should check needs */

		/* avoid clobbering of longlived regs */
		/* let register allocator coalesce */
		if ((q->rewrite & RLEFT) && (shl == SRDIR) /* && isreg(l) */)
			shl = SRREG;

		F2DEBUG(("finduni got cookie\n"));
		if (q->needs & REWRITE)
			break;	/* Done here */

		if (shl >= num)
			continue;
		num = shl;
		idx = ixp[i];

		if (shl == SRDIR)
			break;
	}

	if (num == 4) {
		F2DEBUG(("finduni failed\n"));
	} else
		F2DEBUG(("finduni entry %d(%s)\n", idx, srtyp[num]));

	if (num == 4) {
		if (setuni(p, cookie))
			return FRETRY;
		return FFAIL;
	}
	q = &table[idx];

	sh = shswitch(-1, p->n_left, q->lshape, cookie,
	    q->rewrite & RLEFT, num);
	if (sh == -1)
		sh = ffs(cookie & q->visit & INREGS)-1;
	if (sh == -1)
		sh = 0;

	F2DEBUG(("finduni: node %p (%s)\n", p, prcook(1 << sh)));
	p->n_su = MKIDX(idx, 0);
	SCLASS(p->n_su, sh);
	return sh;
}
Esempio n. 7
0
/*
 * Search for an UMUL table entry that can turn an indirect node into
 * a move from an OREG.
 */
int
findumul(NODE *p, int cookie)
{
	extern int *qtable[];
	struct optab *q = NULL; /* XXX gcc */
	int i, shl = 0, shr = 0, sh;
	int *ixp;

	F2DEBUG(("findumul p %p (%s)\n", p, prcook(cookie)));
	F2WALK(p);

	ixp = qtable[p->n_op];
	for (i = 0; ixp[i] >= 0; i++) {
		q = &table[ixp[i]];

		F2DEBUG(("findumul: ixp %d\n", ixp[i]));
		if (!acceptable(q))		/* target-dependent filter */
			continue;

		if ((q->visit & cookie) == 0)
			continue; /* wrong registers */

		if (ttype(p->n_type, q->rtype) == 0)
			continue; /* Types must be correct */
		

		F2DEBUG(("findumul got types, rshape %s\n", prcook(q->rshape)));
		/*
		 * Try to create an OREG of the node.
		 * Fake left even though it's right node,
		 * to be sure of conversion if going down left.
		 */
		if ((shl = chcheck(p, q->rshape, 0)) == SRNOPE)
			continue;
		
		shr = 0;

		if (q->needs & REWRITE)
			break;	/* Done here */

		F2DEBUG(("findumul got shape %s\n", srtyp[shl]));

		break; /* XXX search better matches */
	}
	if (ixp[i] < 0) {
		F2DEBUG(("findumul failed\n"));
		if (setuni(p, cookie))
			return FRETRY;
		return FFAIL;
	}
	F2DEBUG(("findumul entry %d(%s %s)\n", ixp[i], srtyp[shl], srtyp[shr]));

	sh = shswitch(-1, p, q->rshape, cookie, q->rewrite & RLEFT, shl);
	if (sh == -1)
		sh = ffs(cookie & q->visit & INREGS)-1;

	F2DEBUG(("findumul: node %p (%s)\n", p, prcook(1 << sh)));
	p->n_su = MKIDX(ixp[i], 0);
	SCLASS(p->n_su, sh);
	return sh;
}
Esempio n. 8
0
/*
 * Find a matching assign op.
 *
 * Level assignment for priority:
 *	left	right	prio
 *	-	-	-
 *	direct	direct	1
 *	direct	REG	2
 *	direct	OREG	3
 *	OREG	direct	4
 *	OREG	REG	5
 *	OREG	OREG	6
 */
int
findasg(NODE *p, int cookie)
{
	extern int *qtable[];
	struct optab *q;
	int i, sh, shl, shr, lvl = 10;
	NODE *l, *r;
	int *ixp;
	struct optab *qq = NULL; /* XXX gcc */
	int idx = 0, gol = 0, gor = 0;

	shl = shr = 0;

	F2DEBUG(("findasg tree: %s\n", prcook(cookie)));
	F2WALK(p);

	ixp = qtable[p->n_op];
	l = getlr(p, 'L');
	r = getlr(p, 'R');
	for (i = 0; ixp[i] >= 0; i++) {
		q = &table[ixp[i]];

		F2DEBUG(("findasg: ixp %d\n", ixp[i]));
		if (!acceptable(q))		/* target-dependent filter */
			continue;

		if (ttype(l->n_type, q->ltype) == 0 ||
		    ttype(r->n_type, q->rtype) == 0)
			continue; /* Types must be correct */

		if ((cookie & q->visit) == 0)
			continue; /* must get a result */

		F2DEBUG(("findasg got types\n"));
#ifdef mach_pdp11 /* XXX - check for other targets too */
		if (p->n_op == STASG && ISPTR(l->n_type)) {
			/* Accept lvalue to be in register */
			/* if struct assignment is given a pointer */
			if ((shl = chcheck(l, q->lshape,
			    q->rewrite & RLEFT)) == SRNOPE)
				continue;
		} else
#endif
		{
			if ((shl = tshape(l, q->lshape)) == SRNOPE)
				continue;
			if (shl == SRREG)
				continue;
		}

		F2DEBUG(("findasg lshape %d\n", shl));
		F2WALK(l);

		if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT)) == SRNOPE)
			continue;

		F2DEBUG(("findasg rshape %d\n", shr));
		F2WALK(r);
		if (q->needs & REWRITE)
			break;	/* Done here */

		if (lvl <= (shl + shr))
			continue;

		lvl = shl + shr;
		qq = q;
		idx = ixp[i];
		gol = shl;
		gor = shr;
	}

	if (lvl == 10) {
		F2DEBUG(("findasg failed\n"));
		if (setasg(p, cookie))
			return FRETRY;
		return FFAIL;
	}
	F2DEBUG(("findasg entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));

	sh = -1;
	sh = shswitch(sh, p->n_left, qq->lshape, cookie,
	    qq->rewrite & RLEFT, gol);

	sh = shswitch(sh, p->n_right, qq->rshape, cookie,
	    qq->rewrite & RRIGHT, gor);

#ifdef mach_pdp11 /* XXX all targets? */
	lvl = 0;
	if (cookie == FOREFF)
		lvl = RVEFF, sh = 0;
	else if (cookie == FORCC)
		lvl = RVCC, sh = 0;
	else if (sh == -1) {
		sh = ffs(cookie & qq->visit & INREGS)-1;
#ifdef PCC_DEBUG
		if (sh == -1)
			comperr("findasg bad shape");
#endif
		SCLASS(lvl,sh);
	} else
		SCLASS(lvl,sh);
	p->n_su = MKIDX(idx, lvl);
#else
	if (sh == -1) {
		if (cookie == FOREFF)
			sh = 0;
		else
			sh = ffs(cookie & qq->visit & INREGS)-1;
	}
	F2DEBUG(("findasg: node %p class %d\n", p, sh));

	p->n_su = MKIDX(idx, 0);
	SCLASS(p->n_su, sh);
#endif /* mach_pdp11 */
#ifdef FINDMOPS
	p->n_su &= ~ISMOPS;
#endif
	return sh;
}
Esempio n. 9
0
/*
 * Find the best relation op for matching the two trees it has.
 * This is a sub-version of the function findops() above.
 * The instruction with the lowest grading is emitted.
 *
 * Level assignment for priority:
 *	left	right	prio
 *	-	-	-
 *	direct	direct	1
 *	direct	OREG	2	# make oreg
 *	OREG	direct	2	# make oreg
 *	OREG	OREG	2	# make both oreg
 *	direct	REG	3	# put in reg
 *	OREG	REG	3	# put in reg, make oreg
 *	REG	direct	3	# put in reg
 *	REG	OREG	3	# put in reg, make oreg
 *	REG	REG	4	# put both in reg
 */
int
relops(NODE *p)
{
	extern int *qtable[];
	struct optab *q;
	int i, shl = 0, shr = 0, sh;
	NODE *l, *r;
	int *ixp, idx = 0;
	int lvl = 10, gol = 0, gor = 0;

	F2DEBUG(("relops tree:\n"));
	F2WALK(p);

	l = getlr(p, 'L');
	r = getlr(p, 'R');
	ixp = qtable[p->n_op];
	for (i = 0; ixp[i] >= 0; i++) {
		q = &table[ixp[i]];

		F2DEBUG(("relops: ixp %d\n", ixp[i]));
		if (!acceptable(q))		/* target-dependent filter */
			continue;

		if (ttype(l->n_type, q->ltype) == 0 ||
		    ttype(r->n_type, q->rtype) == 0)
			continue; /* Types must be correct */

		F2DEBUG(("relops got types\n"));
		if ((shl = chcheck(l, q->lshape, 0)) == SRNOPE)
			continue;
		F2DEBUG(("relops lshape %d\n", shl));
		F2WALK(p);
		if ((shr = chcheck(r, q->rshape, 0)) == SRNOPE)
			continue;
		F2DEBUG(("relops rshape %d\n", shr));
		F2WALK(p);
		if (q->needs & REWRITE)
			break;	/* Done here */

		if (lvl <= (shl + shr))
			continue;
		lvl = shl + shr;
		idx = ixp[i];
		gol = shl;
		gor = shr;
	}
	if (lvl == 10) {
		F2DEBUG(("relops failed\n"));
		if (setbin(p))
			return FRETRY;
		return FFAIL;
	}
	F2DEBUG(("relops entry %d(%s %s)\n", idx, srtyp[gol], srtyp[gor]));

	q = &table[idx];

	(void)shswitch(-1, p->n_left, q->lshape, INREGS,
	    q->rewrite & RLEFT, gol);

	(void)shswitch(-1, p->n_right, q->rshape, INREGS,
	    q->rewrite & RRIGHT, gor);

	sh = 0;
	if (q->rewrite & RLEFT)
		sh = ffs(q->lshape & INREGS)-1;
	else if (q->rewrite & RRIGHT)
		sh = ffs(q->rshape & INREGS)-1;

	F2DEBUG(("relops: node %p\n", p));
	p->n_su = MKIDX(idx, 0);
	SCLASS(p->n_su, sh);
	return 0;
}
Esempio n. 10
0
/*
 * Find the best instruction to evaluate the given tree.
 * Best is to match both subnodes directly, second-best is if
 * subnodes must be evaluated into OREGs, thereafter if nodes 
 * must be put into registers.
 * Whether 2-op instructions or 3-op is preferred is depending on in
 * which order they are found in the table.
 * mtchno is set to the count of regs needed for its legs.
 */
int
findops(NODE *p, int cookie)
{
	extern int *qtable[];
	struct optab *q, *qq = NULL;
	int i, shl, shr, *ixp, sh;
	int lvl = 10, idx = 0, gol = 0, gor = 0;
	NODE *l, *r;

	F2DEBUG(("findops node %p (%s)\n", p, prcook(cookie)));
	F2WALK(p);

	ixp = qtable[p->n_op];
	l = getlr(p, 'L');
	r = getlr(p, 'R');
	for (i = 0; ixp[i] >= 0; i++) {
		q = &table[ixp[i]];

		F2DEBUG(("findop: ixp %d str %s\n", ixp[i], q->cstring));
		if (!acceptable(q))		/* target-dependent filter */
			continue;

		if (ttype(l->n_type, q->ltype) == 0 ||
		    ttype(r->n_type, q->rtype) == 0)
			continue; /* Types must be correct */

		if ((cookie & q->visit) == 0)
			continue; /* must get a result */

		F2DEBUG(("findop got types\n"));

		if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE)
			continue;

		F2DEBUG(("findop lshape %s\n", srtyp[shl]));
		F2WALK(l);

		if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT)) == SRNOPE)
			continue;

		F2DEBUG(("findop rshape %s\n", srtyp[shr]));
		F2WALK(r);

		/* Help register assignment after SSA by preferring */
		/* 2-op insns instead of 3-ops */
		if (xssa && (q->rewrite & RLEFT) == 0 && shl == SRDIR)
			shl = SRREG;

		if (q->needs & REWRITE)
			break;  /* Done here */

		if (lvl <= (shl + shr))
			continue;
		lvl = shl + shr;
		qq = q;
		idx = ixp[i];
		gol = shl;
		gor = shr;
	}
	if (lvl == 10) {
		F2DEBUG(("findops failed\n"));
		if (setbin(p))
			return FRETRY;
		return FFAIL;
	}

	F2DEBUG(("findops entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));

	sh = -1;

#ifdef mach_pdp11
	if (cookie == FORCC && p->n_op != AND)	/* XXX - fix */
		cookie = INREGS;
#else
	if (cookie == FORCC)
		cookie = INREGS;
#endif

	sh = shswitch(sh, p->n_left, qq->lshape, cookie,
	    qq->rewrite & RLEFT, gol);
	sh = shswitch(sh, p->n_right, qq->rshape, cookie,
	    qq->rewrite & RRIGHT, gor);

	if (sh == -1) {
		if (cookie == FOREFF || cookie == FORCC)
			sh = 0;
		else
			sh = ffs(cookie & qq->visit & INREGS)-1;
	}
	F2DEBUG(("findops: node %p sh %d (%s)\n", p, sh, prcook(1 << sh)));
	p->n_su = MKIDX(idx, 0);
	SCLASS(p->n_su, sh);
	return sh;
}
Esempio n. 11
0
/*
 * Try to find constructs like "a = a + 1;" and match them together
 * with instructions like "incl a" or "addl $1,a".
 *
 * Level assignment for priority:
 *	left	right	prio
 *	-	-	-
 *	direct	direct	1
 *	direct	REG	2
 *	direct	OREG	3
 *	OREG	direct	4
 *	OREG	REG	5
 *	OREG	OREG	6
 */
int
findmops(NODE *p, int cookie)
{
	extern int *qtable[];
	struct optab *q;
	int i, sh, shl, shr, lvl = 10;
	NODE *l, *r;
	int *ixp;
	struct optab *qq = NULL; /* XXX gcc */
	int idx = 0, gol = 0, gor = 0;

	shl = shr = 0;

	F2DEBUG(("findmops tree: %s\n", prcook(cookie)));
	F2WALK(p);

	l = getlr(p, 'L');
	r = getlr(p, 'R');
	/* See if this is a usable tree to work with */
	/* Currently only check for leaves */
	if (optype(r->n_op) != BITYPE || treecmp(l, r->n_left) == 0)
		return FFAIL;

	F2DEBUG(("findmops is useable\n"));

	/* We can try to find a match.  Use right op */
	ixp = qtable[r->n_op];
	l = getlr(r, 'L');
	r = getlr(r, 'R');

	for (i = 0; ixp[i] >= 0; i++) {
		q = &table[ixp[i]];

		F2DEBUG(("findmops: ixp %d\n", ixp[i]));
		if (!acceptable(q))		/* target-dependent filter */
			continue;

		if (ttype(l->n_type, q->ltype) == 0 ||
		    ttype(r->n_type, q->rtype) == 0)
			continue; /* Types must be correct */

		F2DEBUG(("findmops got types\n"));

		switch (cookie) {
		case FOREFF:
			if ((q->visit & FOREFF) == 0)
				continue; /* Not only for side effects */
			break;
		case FORCC:
			if ((q->visit & FORCC) == 0)
				continue; /* Not only for side effects */
			break;
		default:
			if ((cookie & q->visit) == 0)
				continue; /* Won't match requested shape */
			if (((cookie & INREGS & q->lshape) == 0) || !isreg(l))
				continue; /* Bad return register */
			break;
		}
		F2DEBUG(("findmops cookie\n"));

		/*
		 * left shape must match left node.
		 */
		if ((shl = tshape(l, q->lshape)) != SRDIR && (shl != SROREG))
			continue;

		F2DEBUG(("findmops lshape %s\n", srtyp[shl]));
		F2WALK(l);

		if ((shr = chcheck(r, q->rshape, 0)) == SRNOPE)
			continue;

		F2DEBUG(("findmops rshape %s\n", srtyp[shr]));

		/*
		 * Only allow RLEFT. XXX
		 */
		if ((q->rewrite & (RLEFT|RRIGHT)) != RLEFT)
			continue;

		F2DEBUG(("rewrite OK\n"));

		F2WALK(r);
		if (q->needs & REWRITE)
			break;	/* Done here */

		if (lvl <= (shl + shr))
			continue;

		lvl = shl + shr;
		qq = q;
		idx = ixp[i];
		gol = shl;
		gor = shr;
	}

	if (lvl == 10)
		return FFAIL;
	F2DEBUG(("findmops entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));

	/*
	 * Now we're here and have a match. left is semi-direct and 
	 * right may be anything.
	 */

	sh = -1;
	sh = shswitch(sh, p->n_left, qq->lshape, cookie,
	    qq->rewrite & RLEFT, gol);
	sh = shswitch(sh, r, qq->rshape, cookie, 0, gor);

	if (sh == -1) {
		if (cookie & (FOREFF|FORCC))
			sh = 0;
		else
			sh = ffs(cookie & qq->visit & INREGS)-1;
	}
	F2DEBUG(("findmops done: node %p class %d\n", p, sh));

	/* Trickery:  Set table index on assign to op instead */
	/* gencode() will remove useless nodes */
	p->n_su = MKIDX(idx, 0);
	p->n_su |= ISMOPS; /* XXX tell gencode to reduce the right tree */
	SCLASS(p->n_su, sh);

	return sh;
}