Ejemplo n.º 1
0
int bool_expr(boolean_t op, oprtype *addr)
{
	oprtype x;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	INCREMENT_EXPR_DEPTH;
	if (!eval_expr(&x))
	{
		DECREMENT_EXPR_DEPTH;
		return FALSE;
	}
	assert(TRIP_REF == x.oprclass);
	coerce(&x, OCT_BOOL);
	bx_tail(x.oprval.tref, op, addr);
	DECREMENT_EXPR_DEPTH;
	return TRUE;
}
Ejemplo n.º 2
0
int bool_expr(bool op,oprtype *addr)
{
	oprtype x;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	if (!(TREF(expr_depth))++)
		TREF(expr_start) = TREF(expr_start_orig) = NULL;
	if (!eval_expr(&x))
	{
		TREF(expr_depth) = 0;
		return FALSE;
	}
	coerce(&x, OCT_BOOL);
	if (!(--(TREF(expr_depth))))
		TREF(shift_side_effects) = FALSE;
	assert(x.oprclass == TRIP_REF);
	bx_tail(x.oprval.tref, op, addr);
	return TRUE;
}
Ejemplo n.º 3
0
void bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean_t sense, oprtype *addr)
{
	boolean_t	expr_fini;
	oprtype		*adj_addr, *i, *p;
	tbp		*tripbp;
	triple		*ref0, *ref1, *ref2, *t0, *t1;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(((1 & sense) == sense) && ((1 & jmp_to_next) == jmp_to_next) && ((1 & jmp_type_one) == jmp_type_one));
	assert((TRIP_REF == t->operand[0].oprclass) && (TRIP_REF == t->operand[1].oprclass));
	if (jmp_to_next)
	{
		p = (oprtype *)mcalloc(SIZEOF(oprtype));
		*p = put_tjmp(t);
	} else
		p = addr;
	if (GTM_BOOL == TREF(gtm_fullbool) || !TREF(saw_side_effect))
	{	/* nice simple short circuit */
		assert(NULL == TREF(boolchain_ptr));
		bx_tail(t->operand[0].oprval.tref, jmp_type_one, p);
		bx_tail(t->operand[1].oprval.tref, sense, addr);
		t->opcode = OC_NOOP;
		t->operand[0].oprclass = t->operand[1].oprclass = NOCLASS;
		return;
	}
	/* got a side effect and don't want them short circuited */
	/* This code violates info hiding big-time and relies on the original technique of setting up a jump ladder
	 * then it changes the jumps into stotemps and creates a new ladder using the saved evaluations
	 * for the relocated jumps to use for controlling conditional transfers, When the stotemps reference mvals,
	 * they are optimized away when possible. The most interesting part is getting the addresses for the new jump
	 * operands (targets) - see comment below. In theory we could turn this technique on and off around each side effect,
	 * but that's even more complicated, requiring additional instructions, and we don't predict the typical boolean
	 * expression has enough subexpressions to justify the extra trouble, although the potential pay-back would be to
	 * avoid unnecessary global references - again, not expecting that many in a typical boolean expresion.
	 */
	assert(TREF(shift_side_effects));
	if (expr_fini = (NULL == TREF(boolchain_ptr)))				/* NOTE assignment */
	{									/* initialize work on boolean section of the AST */
		TREF(boolchain_ptr) = &(TREF(boolchain));
		dqinit(TREF(boolchain_ptr), exorder);
		t0 = t->exorder.fl;
		if (NULL == TREF(bool_targ_ptr))
		{								/* first time - set up anchor */
			TREF(bool_targ_ptr) = &(TREF(bool_targ_anchor));	/* mcalloc won't persist over multiple complies */
			dqinit(TREF(bool_targ_ptr), que);
		} else								/* queue should be empty */
			assert((TREF(bool_targ_ptr) == (TREF(bool_targ_ptr))->que.fl)
				&& (TREF(bool_targ_ptr) == (TREF(bool_targ_ptr))->que.bl));
		/* ex_tail wraps bools that produce a value with OC_BOOLINIT (clr) and OC_BOOLFINI (set) */
		assert((OC_BOOLFINI != t0->opcode)
			|| ((OC_COMVAL == t0->exorder.fl->opcode) && (TRIP_REF == t0->operand[0].oprclass)));
	}
	for (i = t->operand; i < ARRAYTOP(t->operand); i++)
	{
		assert(NULL != TREF(boolchain_ptr));
		t1 = i->oprval.tref;
		if (&(t->operand[0]) == i)
			bx_tail(t1, jmp_type_one, p);				/* do normal transform */
		else
		{	/* operand[1] */
			bx_tail(t1, sense, addr);				/* do normal transform */
			if (!expr_fini)
				break;						/* only need to relocate last operand[1] */
		}
		if (OC_NOOP == t1->opcode)
		{	/* the technique of sprinkling noops means fishing around for the actual instruction */
			do
			{
				t1 = t1->exorder.bl;
				assert(TREF(curtchain) != t1->exorder.bl);
			} while (OC_NOOP == t1->opcode);
			if ((oc_tab[t1->opcode].octype & OCT_JUMP) && (OC_JMPTSET != t1->opcode) && (OC_JMPTCLR != t1->opcode))
				t1 = t1->exorder.bl;
			if (OC_NOOP == t1->opcode)
			{
				for (t1 = i->oprval.tref; OC_NOOP == t1->opcode; t1 = t1->exorder.fl)
					assert(TREF(curtchain) != t1->exorder.fl);
			}
		}
		assert(OC_NOOP != t1->opcode);
		assert((oc_tab[t1->exorder.fl->opcode].octype & OCT_JUMP)
			||(OC_JMPTSET != t1->exorder.fl->opcode) || (OC_JMPTCLR != t1->exorder.fl->opcode));
		ref0 = maketriple(t1->opcode);					/* copy operation for place in new ladder */
		ref1 = (TREF(boolchain_ptr))->exorder.bl;			/* common setup for above op insert */
		switch (t1->opcode)
		{								/* time to subvert original jump ladder entry */
			case OC_COBOOL:
				/* insert COBOOL and copy of following JMP in boolchain; overlay them with STOTEMP and NOOP  */
				assert(TRIP_REF == t1->operand[0].oprclass);
				dqins(ref1, exorder, ref0);
				if (oc_tab[t1->operand[0].oprval.tref->opcode].octype & OCT_MVAL)
				{						/* do we need a STOTEMP? */
					switch (t1->operand[0].oprval.tref->opcode)
					{
						case OC_INDGLVN:		/* indirect actions not happy without STOTEMP */
						case OC_INDNAME:
						case OC_VAR:			/* variable could change so must save it */
							t1->opcode = OC_STOTEMP;
							ref0->operand[0] = put_tref(t1);/* new COBOOL points to this OC_STOTEMP */
							break;
						default:			/* else no temporary if it's mval */
							ref0->operand[0] = put_tref(t1->operand[0].oprval.tref);
							t1->opcode = OC_NOOP;
							t1->operand[0].oprclass = NOCLASS;
					}
				} else
				{						/* make it an mval instead of COBOOL now */
					t1->opcode = OC_COMVAL;
					ref0->operand[0] = put_tref(t1);	/* new COBOOL points to this OC_COMVAL  */
				}
				t1 = t1->exorder.fl;
				ref0 = maketriple(t1->opcode);			/* create new jmp on result of coerce */
				ref0->operand[0] = t1->operand[0];
				t1->opcode = OC_NOOP;				/* wipe out original jmp */
				t1->operand[0].oprclass = NOCLASS;
				break;
			case OC_CONTAIN:
			case OC_EQU:
			case OC_FOLLOW:
			case OC_NUMCMP:
			case OC_PATTERN:
			case OC_SORTS_AFTER:
				/* insert copies of orig OC and following JMP in boolchain & overly originals with STOTEMPs */
				assert(TRIP_REF == t1->operand[0].oprclass);
				assert(TRIP_REF == t1->operand[1].oprclass);
				dqins(ref1, exorder, ref0);
				if (OC_VAR == t1->operand[0].oprval.tref->opcode)
				{						/* VAR could change so must save it */
					t1->opcode = OC_STOTEMP;		/* overlay the original op with a STOTEMP */
					ref0->operand[0] = put_tref(t1);	/* new op points to thi STOTEMP */
				} else
				{						/* no need for a temporary unless it's a VAR */
					ref0->operand[0] = put_tref(t1->operand[0].oprval.tref);
					t1->opcode = OC_NOOP;
				}
				ref1 = t1;
				t1 = t1->exorder.fl;
				ref2 = maketriple(t1->opcode);			/* copy jmp */
				ref2->operand[0] = t1->operand[0];
				if (OC_VAR == ref1->operand[1].oprval.tref->opcode)
				{						/* VAR could change so must save it */
					ref0->operand[1] = put_tref(t1);	/* new op points to STOTEMP overlaying the jmp  */
					t1->operand[0] = ref1->operand[1];
					t1->opcode = OC_STOTEMP;		/* overlay jmp with 2nd STOTEMP */
				} else
				{						/* no need for a temporary unless it's a VAR */
					ref0->operand[1] = put_tref(ref1->operand[1].oprval.tref);
					t1->opcode = OC_NOOP;
					t1->operand[0].oprclass = NOCLASS;
				}
				if (OC_NOOP == ref1->opcode)			/* does op[0] need cleanup? */
					ref1->operand[0].oprclass = ref1->operand[1].oprclass = NOCLASS;
				ref0 = ref2;
				break;
			case OC_JMPTSET:
			case OC_JMPTCLR:
										/* move copy of jmp to boolchain and NOOP it */
				ref0->operand[0] = t1->operand[0];		/* new jmpt gets old target */
				ref2 = maketriple(OC_NOOP);			/* insert a NOOP in new chain inplace of COBOOL */
				dqins(ref1, exorder, ref2);
				t1->opcode = OC_NOOP;				/* wipe out original jmp */
				t1->operand[0].oprclass = NOCLASS;
				break;
			default:
				assertpro(FALSE);
		}
		assert((OC_STOTEMP == t1->opcode) || (OC_NOOP == t1->opcode) || (OC_COMVAL == t1->opcode));
		assert(oc_tab[ref0->opcode].octype & OCT_JUMP);
		ref1 = (TREF(boolchain_ptr))->exorder.bl;
		dqins(ref1, exorder, ref0);					/* common insert for new jmp */
	}
	assert(oc_tab[t->opcode].octype & OCT_BOOL);
	t->opcode = OC_NOOP;							/* wipe out the original boolean op */
	t->operand[0].oprclass = t->operand[1].oprclass = NOCLASS;
	tripbp = &t->jmplist;							/* borrow jmplist to track jmp targets */
	assert(NULL == tripbp->bpt);
	assert((tripbp == tripbp->que.fl) && (tripbp == tripbp->que.bl));
	tripbp->bpt = jmp_to_next ? (TREF(boolchain_ptr))->exorder.bl : ref0;	/* point op triple at op[1] position or op[0] */
	dqins(TREF(bool_targ_ptr), que, tripbp);				/* queue jmplist for clean-up */
	if (!expr_fini)
		return;
	/* time to deal with new jump ladder */
	assert(NULL != TREF(boolchain_ptr));
	assert(NULL != TREF(bool_targ_ptr));
	assert(TREF(bool_targ_ptr) != (TREF(bool_targ_ptr))->que.fl);
	assert(t0->exorder.bl == t);
	assert(t0 == t->exorder.fl);
	dqadd(t, TREF(boolchain_ptr), exorder);					/* insert the new jump ladder */
	ref0 = (TREF(boolchain_ptr))->exorder.bl->exorder.fl;
	t0 = t->exorder.fl;
	if (ref0 == TREF(curtchain))
	{									/* add a safe target */
		newtriple(OC_NOOP);
		ref0 = (TREF(curtchain))->exorder.bl;
	}
	assert((OC_COBOOL == t0->opcode) ||(OC_JMPTSET != t0->opcode) || (OC_JMPTCLR != t0->opcode)) ;
	t0 = t0->exorder.fl;
	assert(oc_tab[t0->opcode].octype & OCT_JUMP);
	for (; (t0 != ref0) && oc_tab[t0->opcode].octype & OCT_JUMP; t0 = t0->exorder.fl)
	{									/* process replacement jmps */
		adj_addr = &t0->operand[0];
		assert(INDR_REF == adj_addr->oprclass);
		if (NULL != (t1 = (adj_addr = adj_addr->oprval.indr)->oprval.tref))
		{								/*  need to adjust target; NOTE assignments above */
			if (OC_BOOLFINI != t1->opcode)
			{							/* not past the end of the new chain */
				assert(TJMP_REF == adj_addr->oprclass);
				if ((t == t1) || (t1 == ref0))
					ref1 = ref0;				/* adjust to end of boolean expression */
				else
				{						/* old target should have jmplist entry */
					/* from the jmp jmplisted in the old target we move past the next
					 * test (or NOOP) and jmp which correspond to the old target and pick
					 * the subsequent test (or NOOP) and jmp which correspond to those that originally followed
					 * the logic after the old target and are therefore the appropriate new target for this jmp
					 */
					assert(OC_NOOP == t1->opcode);
					assert(&(t1->jmplist) != t1->jmplist.que.fl);
					assert(NULL != t1->jmplist.bpt);
					assert(oc_tab[t1->jmplist.bpt->opcode].octype & OCT_JUMP);
					ref1 = t1->jmplist.bpt->exorder.fl;
					assert((oc_tab[ref1->opcode].octype & OCT_BOOL) || (OC_NOOP == ref1->opcode));
					assert(oc_tab[ref1->exorder.fl->opcode].octype & OCT_JUMP);
					ref1 = ref1->exorder.fl->exorder.fl;
					assert((oc_tab[ref1->opcode].octype & OCT_BOOL) || (OC_BOOLFINI == ref1->opcode)
						|| ((OC_NOOP == ref1->opcode) && ((OC_JMPTCLR == ref1->exorder.fl->opcode)
						|| (OC_JMPTSET == ref1->exorder.fl->opcode)
						|| (TREF(curtchain) == ref1->exorder.fl))));
				}
				t0->operand[0] = put_tjmp(ref1);		/* no indrection simplifies later interations */
			}
		}
		t0 = t0->exorder.fl;
		if ((OC_BOOLFINI == t0->opcode) || (TREF(curtchain) == t0->exorder.fl))
			break;
		assert((oc_tab[t0->opcode].octype & OCT_BOOL)
			|| (OC_JMPTSET == t0->exorder.fl->opcode) || (OC_JMPTCLR == t0->exorder.fl->opcode));
	}
	dqloop(TREF(bool_targ_ptr), que, tripbp)				/* clean up borrowed jmplist entries */
	{
		dqdel(tripbp, que);
		tripbp->bpt = NULL;
	}
Ejemplo n.º 4
0
int bool_expr(boolean_t sense, oprtype *addr)
/*
 * invoked to resolve expresions that are by definition coerced to Boolean, which include
 * IF arguments, $SELECT() arguments, and postconditionals for both commands and arguments
 * IF is the only one that comes in with the "TRUE" sense
 * *addr winds up as an pointer to a jump operand, which the caller fills in
 */
{
	boolean_t	is_com, tv;
	uint4		bexprs;
	opctype		c;
	oprtype		x;
	triple		*bitrip, *t, *t0, *t1, *t2;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	INCREMENT_EXPR_DEPTH;
	if (!eval_expr(&x))
	{
		DECREMENT_EXPR_DEPTH;
		return FALSE;
	}
	UNARY_TAIL(&x);
	if (OC_LIT == (x.oprval.tref)->opcode)
	{	/* if its just a literal don't waste time */
		DECREMENT_EXPR_DEPTH;
		return TRUE;
	}
	assert(TRIP_REF == x.oprclass);
	coerce(&x, OCT_BOOL);
	t = x.oprval.tref;
	for (t1 = t; ; t1 = t2)
	{
		assert(TRIP_REF == t1->operand[0].oprclass);
		t2 = t1->operand[0].oprval.tref;
		if (!(oc_tab[t2->opcode].octype & OCT_BOOL))
			break;
	}
	if (OC_INDGLVN == t2->opcode)
		t1 = t2;	/* because of how we process indirection, can't insert a NOOP between COBOOL and INDGLGN */
	bitrip = maketriple(OC_BOOLINIT);						/* a marker we'll delete later */
	dqins(t1->exorder.bl, exorder, bitrip);
	assert(TREF(curtchain) ==  t->exorder.fl);
	(TREF(curtchain))->operand[0] = put_tref(bitrip);
	bx_tail(t, sense, addr);
	(TREF(curtchain))->operand[0].oprclass = NO_REF;
	assert(t == x.oprval.tref);
	DECREMENT_EXPR_DEPTH;
	for (bexprs = 0, t0 = t; bitrip != t0; t0 = t0->exorder.bl)
	{
		if (OCT_JUMP & oc_tab[c = t0->opcode].octype)				/* WARNING assignment */
		{
			switch (t0->opcode)
			{
				case OC_JMPFALSE:
				case OC_JMPTRUE:
					assert(INDR_REF == t0->operand[0].oprclass);
					t0->opcode = (OC_JMPTRUE == t0->opcode) ? OC_NOOP : OC_JMP;
					t0->operand[0].oprclass = (OC_NOOP ==  t0->opcode) ? NO_REF : INDR_REF;
					if (!bexprs++)
						t = t0;
					break;
				default:
					bexprs += 2;
			}
		}
	}
	bitrip->opcode = OC_NOOP;							/* ditch it after it served us */
	if (1 == bexprs)
	{	/* if there is just a one JMP TRUE / FALSE turn it into a literal */
		assert((OC_NOOP ==  t->opcode) || (OC_JMP ==  t->opcode));
		PUT_LITERAL_TRUTH((OC_NOOP == t->opcode) ^ sense, t);
		t->opcode = OC_LIT;
	} else if (!bexprs && (OC_COBOOL == t->opcode) && (OC_LIT == (t0 = t->operand[0].oprval.tref)->opcode)
		&& ((OC_JMPEQU == t->exorder.fl->opcode) || (OC_JMPNEQ == t->exorder.fl->opcode)))
	{	/* just one jump based on a literal, so resolve it */
		t->opcode = OC_NOOP;
		t->operand[0].oprclass = NO_REF;
		t = t->exorder.fl;
		dqdel(t, exorder);
		unuse_literal(&t0->operand[0].oprval.mlit->v);
		tv = (((0 == t0->operand[0].oprval.mlit->v.m[1]) ? OC_JMPNEQ : OC_JMPEQU) == t->opcode) ^ sense;
		PUT_LITERAL_TRUTH(tv, t0);
	}
	return TRUE;
}
Ejemplo n.º 5
0
void bx_tail(triple *t, boolean_t sense, oprtype *addr)
/*
 * triple	  *t;		triple to be processed
 *boolean_t sense;	code to be generated is jmpt or jmpf
 *oprtype	  *addr;	address to jmp
 */
{
	triple *ref;
	oprtype *p;

	assert((1 & sense) == sense);
	assert(oc_tab[t->opcode].octype & OCT_BOOL);
	assert(TRIP_REF == t->operand[0].oprclass);
	assert((TRIP_REF == t->operand[1].oprclass) || (NOCLASS == t->operand[1].oprclass));
	switch (t->opcode)
	{
	case OC_COBOOL:
		ex_tail(&t->operand[0]);
		if (OC_GETTRUTH == t->operand[0].oprval.tref->opcode)
		{
			dqdel(t->operand[0].oprval.tref, exorder);
			t->opcode = sense ? OC_JMPTSET : OC_JMPTCLR;
			t->operand[0] = put_indr(addr);
			return;
		}
		ref = maketriple(sense ? OC_JMPNEQ : OC_JMPEQU);
		ref->operand[0] = put_indr(addr);
		dqins(t, exorder, ref);
		return;
	case OC_COM:
		bx_tail(t->operand[0].oprval.tref, !sense, addr);
		t->opcode = OC_NOOP;
		t->operand[0].oprclass = 0;
		return;
	case OC_NEQU:
		sense = !sense;
		/* caution: fall through */
	case OC_EQU:
		bx_relop(t, OC_EQU, sense ? OC_JMPNEQ : OC_JMPEQU, addr);
		break;
	case OC_NPATTERN:
		sense = !sense;
		/* caution: fall through */
	case OC_PATTERN:
		bx_relop(t, OC_PATTERN, sense ? OC_JMPNEQ : OC_JMPEQU, addr);
		break;
	case OC_NFOLLOW:
		sense = !sense;
		/* caution: fall through */
	case OC_FOLLOW:
		bx_relop(t, OC_FOLLOW, sense ? OC_JMPGTR : OC_JMPLEQ, addr);
		break;
	case OC_NSORTS_AFTER:
		sense = !sense;
		/* caution: fall through */
	case OC_SORTS_AFTER:
		bx_relop(t, OC_SORTS_AFTER, sense ? OC_JMPGTR : OC_JMPLEQ, addr);
		break;
	case OC_NCONTAIN:
		sense = !sense;
		/* caution: fall through */
	case OC_CONTAIN:
		bx_relop(t, OC_CONTAIN, sense ? OC_JMPNEQ : OC_JMPEQU, addr);
		break;
	case OC_NGT:
		sense = !sense;
		/* caution: fall through */
	case OC_GT:
		bx_relop(t, OC_NUMCMP, sense ? OC_JMPGTR : OC_JMPLEQ, addr);
		break;
	case OC_NLT:
		sense = !sense;
		/* caution: fall through */
	case OC_LT:
		bx_relop(t, OC_NUMCMP, sense ? OC_JMPLSS : OC_JMPGEQ, addr);
		break;
	case OC_NAND:
		sense = !sense;
		/* caution: fall through */
	case OC_AND:
		bx_boolop(t, FALSE, sense, sense, addr);
		return;
	case OC_NOR:
		sense = !sense;
		/* caution: fall through */
	case OC_OR:
		bx_boolop(t, TRUE, !sense, sense, addr);
		return;
	default:
		GTMASSERT;
	}
	for (p = t->operand ; p < ARRAYTOP(t->operand); p++)
		if (TRIP_REF == p->oprclass)
			ex_tail(p);
	return;
}