oldgaa_error_code  PRIVATE
oldgaa_evaluate_conditions(oldgaa_sec_context_ptr    sc,
                           oldgaa_cond_bindings_ptr  conditions,
                           oldgaa_options_ptr        options)
{
    oldgaa_error_code         oldgaa_status = OLDGAA_NO;
    oldgaa_cond_bindings_ptr  cond       = conditions;
    int                    was_no     = FALSE, was_maybe = FALSE;

    while(cond) { /* walk throug condition list */
        oldgaa_status = OLDGAA_MAYBE;

        oldgaa_status =  evaluate_condition(sc, cond->condition, options);

        if(oldgaa_status == OLDGAA_NO)    was_no    = TRUE;
        if(oldgaa_status == OLDGAA_MAYBE) was_maybe = TRUE;

        cond = cond->next;
    }

    if(was_no)    return OLDGAA_NO;
    if(was_maybe) return OLDGAA_MAYBE;

    return OLDGAA_YES;
}
Example #2
0
/*
 *	Evaluate an 'if' statement
 */
static int evaluate_if(policy_state_t *state, const policy_item_t *item)
{
	int rcode;
	const policy_if_t *this;

	this = (const policy_if_t *) item;

	/*
	 *	evaluate_condition calls itself recursively.
	 *	We should probably allocate a new state, instead.
	 */
	rcode = evaluate_condition(state, this->condition);
	debug_evaluate("IF condition returned %s\n",
	       rcode ? "true" : "false");
	if (rcode) {
		rcode = policy_stack_push(state, this->if_true);
		if (!rcode) return rcode;
	} else if (this->if_false) {
		rcode = policy_stack_push(state, this->if_false);
		if (!rcode) return rcode;
	}

	/*
	 *	'if' can fail, if the block it's processing fails.
	 */
	return 1;;
}
Example #3
0
File: help.c Project: Vortac/atheme
static bool evaluate_condition(sourceinfo_t *si, const char *s)
{
	char word[80];
	char *p, *q;

	while (*s == ' ' || *s == '\t')
		s++;
	if (*s == '!')
		return !evaluate_condition(si, s + 1);
	mowgli_strlcpy(word, s, sizeof word);
	p = strchr(word, ' ');
	if (p != NULL)
	{
		*p++ = '\0';
		while (*p == ' ' || *p == '\t')
			p++;
	}
	if (!strcmp(word, "halfops"))
		return ircd->uses_halfops;
	else if (!strcmp(word, "owner"))
		return ircd->uses_owner;
	else if (!strcmp(word, "protect"))
		return ircd->uses_protect;
	else if (!strcmp(word, "anyprivs"))
		return has_any_privs(si);
	else if (!strcmp(word, "priv"))
	{
		if (p != NULL && (q = strchr(p, ' ')) != NULL)
			*q = '\0';
		return has_priv(si, p);
	}
	else if (!strcmp(word, "module"))
	{
		if (p != NULL && (q = strchr(p, ' ')) != NULL)
			*q = '\0';
		return module_find_published(p) != NULL;
	}
	else if (!strcmp(word, "auth"))
		return me.auth != AUTH_NONE;
	else
		return false;
}
Example #4
0
/*
 *	Evaluate a 'packet .= {attrs}' statement
 */
static int evaluate_attr_list(policy_state_t *state, const policy_item_t *item)
{
	const policy_attributes_t *this;
	VALUE_PAIR **vps = NULL;
	VALUE_PAIR *vp, *head, **tail;
	const policy_item_t *attr;
	policy_lex_t this_how;

	this = (const policy_attributes_t *) item;

	switch (this->where) {
	case POLICY_RESERVED_CONTROL:
		vps = &(state->request->config_items);
		break;

	case POLICY_RESERVED_REQUEST:
		vps = &(state->request->packet->vps);
		break;

	case POLICY_RESERVED_REPLY:
		vps = &(state->request->reply->vps);
		break;

#ifdef WITH_PROXY
	case POLICY_RESERVED_PROXY_REQUEST:
		if (!state->request->proxy) return 0; /* FIXME: print error */
		vps = &(state->request->proxy->vps);
		break;

	case POLICY_RESERVED_PROXY_REPLY:
		if (!state->request->proxy_reply) return 0; /* FIXME: print error */
		vps = &(state->request->proxy_reply->vps);
		break;
#endif

	default:
		return 0;
	}

	head = NULL;
	tail = &head;

	for (attr = this->attributes; attr != NULL; attr = attr->next) {
		if (attr->type != POLICY_TYPE_ASSIGNMENT) {
			fprintf(stderr, "bad assignment in attribute list at line %d\n", attr->lineno);
			pairfree(&head);
			return 0;
		}

		vp = assign2vp(state->request, (const policy_assignment_t *) attr);
		if (!vp) {
			fprintf(stderr, "Failed to allocate VP\n");
			pairfree(&head);
			return 0;
		}
		*tail = vp;
		tail = &(vp->next);
	}

	this_how = this->how;
 retry_how:
	switch (this_how) {
	case POLICY_LEX_SET_EQUALS: /* dangerous: removes all previous things! */
		pairfree(vps);
		*vps = head;
		break;

	case POLICY_LEX_AFTER_TAIL_ASSIGN:
		pairmove(vps, &head);
		pairfree(&head);
		break;

	case POLICY_LEX_ASSIGN: /* 'union' */
		pairmove(vps, &head);
		pairfree(&head);
		break;

	case POLICY_LEX_BEFORE_HEAD_ASSIGN:
		pairmove(&head, vps);
		pairfree(vps);
		*vps = head;
		break;

	case POLICY_LEX_AFTER_TAIL_EQUALS:
	case POLICY_LEX_CONCAT_EQUALS:
		pairadd(vps, head);
		break;

	case POLICY_LEX_BEFORE_HEAD_EQUALS:
		pairadd(&head, *vps);
		*vps = head;
		break;

	case POLICY_LEX_BEFORE_WHERE_EQUALS:
	case POLICY_LEX_AFTER_WHERE_EQUALS:
	case POLICY_LEX_BEFORE_WHERE_ASSIGN:
	case POLICY_LEX_AFTER_WHERE_ASSIGN:
		/* find location*/
		{
			VALUE_PAIR *vpprev = NULL, *vpnext = NULL, *lvp;

			for(lvp = *vps; lvp; vpprev = lvp, lvp = lvp->next) {
				vpnext = lvp->next;
				lvp->next = NULL;
				if (evaluate_condition(state, this->where_loc))
					break;
				lvp->next = vpnext;
			}

			if (lvp) { 
				switch(this_how) {
				case POLICY_LEX_BEFORE_WHERE_EQUALS:
				case POLICY_LEX_BEFORE_WHERE_ASSIGN:
					if (vpprev) {
						lvp->next = vpnext;
						vpnext = lvp;
						vpprev->next = NULL;
						lvp = vpprev;
					}
				default: /* always reached */
					break;
				}

				switch(this_how) {
				case POLICY_LEX_BEFORE_WHERE_EQUALS:
					if (vpprev) 
						pairadd(&lvp, head);
					else
						*vps = lvp = head;
					break;
 				case POLICY_LEX_AFTER_WHERE_EQUALS:
 					pairadd(&lvp, head);
					break;
				case POLICY_LEX_BEFORE_WHERE_ASSIGN:
					if (vpprev) {
						pairmove(&lvp, &head);
						pairfree(&head);
					}
					else
						*vps = lvp = head;
					break;
				case POLICY_LEX_AFTER_WHERE_ASSIGN:
					pairmove(&lvp, &head);
					pairfree(&head);
					break;
				default:/*never reached*/
					break;
				}	
				for( ; lvp && lvp->next; lvp = lvp->next);
				if (lvp)
					lvp->next = vpnext;
				break;
			}

			switch(this_how) {
				case POLICY_LEX_BEFORE_WHERE_EQUALS:
					this_how = POLICY_LEX_BEFORE_HEAD_EQUALS;
					break;
				case POLICY_LEX_AFTER_WHERE_EQUALS:
					this_how = POLICY_LEX_AFTER_TAIL_EQUALS;
					break;
				case POLICY_LEX_BEFORE_WHERE_ASSIGN:
					this_how = POLICY_LEX_BEFORE_HEAD_ASSIGN;
					break;
				case POLICY_LEX_AFTER_WHERE_ASSIGN:
					this_how = POLICY_LEX_AFTER_TAIL_ASSIGN;
					break;
				default: /*never reached*/
					break;
			}
			goto retry_how; 
		}
		/* FALL-THROUGH */

	default:
		fprintf(stderr, "HUH?\n");
		pairfree(&head);
		return 0;
	}

	state->rcode = RLM_MODULE_UPDATED; /* we did stuff */

	return 1;
}
Example #5
0
/*
 *	Evaluate a condition
 */
static int evaluate_condition(policy_state_t *state, const policy_item_t *item)
{
	int rcode;
	const policy_condition_t *this;
	VALUE_PAIR *vp = NULL;
	const char *data = NULL;
	int compare;
#ifdef HAVE_REGEX_H
	regex_t reg;
#endif
	char buffer[256];
	char lhs_buffer[2048];

	this = (const policy_condition_t *) item;

 redo:
	/*
	 *	FIXME: Don't always do this...
	 */
	if (this->compare != POLICY_LEX_L_BRACKET) {
		if (this->lhs_type == POLICY_LEX_FUNCTION) {
			/*
			 *	We can't call evaluate_call here,
			 *	because that just pushes stuff onto
			 *	the stack, and we want to actually
			 *	evaluate all of it...
			 */
			rcode = policy_evaluate_name(state, this->lhs);
			data = fr_int2str(policy_return_codes, rcode, "???");
			strlcpy(lhs_buffer, data, sizeof(lhs_buffer)); /* FIXME: yuck */
		} else if (this->lhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING) {
			if (radius_xlat(lhs_buffer, sizeof(lhs_buffer), this->lhs,
					state->request, NULL, NULL) > 0) {
				data = lhs_buffer;
			}
		}
	}

	switch (this->compare) {
	case POLICY_LEX_L_BRACKET: /* nested brackets are a special case */
		rcode = evaluate_condition(state, this->child);
		break;

	case POLICY_LEX_L_NOT:
		rcode = evaluate_condition(state, this->child);
		rcode = (rcode == FALSE); /* reverse sense of test */
		break;

	case POLICY_LEX_CMP_FALSE: /* non-existence */
		if (this->lhs_type == POLICY_LEX_BARE_WORD) {
			vp = find_vp(state->request, this->lhs);
			rcode = (vp == NULL);
		} else {
			rcode = (data == NULL);
		}
		break;

	case POLICY_LEX_CMP_TRUE: /* existence */
		if (this->lhs_type == POLICY_LEX_BARE_WORD) {
			vp = find_vp(state->request, this->lhs);
			rcode = (vp != NULL);
		} else {
			rcode = (data != NULL);
		}
		break;

	default:		/* process other comparisons */
		if ((this->compare != POLICY_LEX_CMP_EQUALS) &&
#ifdef HAVE_REGEX_H
		    (this->compare != POLICY_LEX_RX_EQUALS) &&
		    (this->compare != POLICY_LEX_RX_NOT_EQUALS) &&
#endif
		    (this->compare != POLICY_LEX_LT) &&
		    (this->compare != POLICY_LEX_GT) &&
		    (this->compare != POLICY_LEX_LE) &&
		    (this->compare != POLICY_LEX_GE) &&
		    (this->compare != POLICY_LEX_CMP_NOT_EQUALS)) {
			fprintf(stderr, "%d: bad comparison\n",
				this->item.lineno);
			return FALSE;
		}

		if (this->lhs_type == POLICY_LEX_BARE_WORD) {
			VALUE_PAIR *myvp;

			vp = find_vp(state->request, this->lhs);

			/*
			 *	A op B is FALSE if A doesn't
			 *	exist.
			 */
			if (!vp) {
				rcode = FALSE;
				break;
			}

			/*
			 *	FIXME: Move sanity checks to
			 *	post-parse code, so we don't do
			 *	it on every packet.
			 */
			vp_prints_value(buffer, sizeof(buffer), vp, 0);
			myvp = pairmake(vp->name, this->rhs, T_OP_EQ);
			if (!myvp) return FALSE; /* memory failure */
			data = buffer;

			/*
			 *	FIXME: What to do about comparisons
			 *	where vp doesn't exist?  Right now,
			 *	"simplepaircmp" returns -1, which is
			 *	probably a bad idea.  it should
			 *	instead take an operator, a pointer to
			 *	the comparison result, and return
			 *	"true/false" for "comparions
			 *	succeeded/failed", which are different
			 *	error codes than "comparison is less
			 *	than, equal to, or greater than zero".
			 */
			compare = radius_callback_compare(state->request,
							  vp, myvp, NULL, NULL);
			pairfree(&myvp);

		} else {
			/*
			 *	FIXME: Do something for RHS type?
			 */
			fr_printf_log("CMP %s %s\n", lhs_buffer, this->rhs);
			compare = strcmp(lhs_buffer, this->rhs);
		}

		debug_evaluate("CONDITION COMPARE %d\n", compare);

		switch (this->compare) {
		case POLICY_LEX_CMP_EQUALS:
			rcode = (compare == 0);
			break;

		case POLICY_LEX_CMP_NOT_EQUALS:
			rcode = (compare != 0);
			break;

		case POLICY_LEX_LT:
			rcode = (compare < 0);
			break;

		case POLICY_LEX_GT:
			rcode = (compare > 0);
			break;

		case POLICY_LEX_LE:
			rcode =(compare <= 0);
			break;

		case POLICY_LEX_GE:
			rcode = (compare >= 0);
			break;

#ifdef HAVE_REGEX_H
		case POLICY_LEX_RX_EQUALS:
		{ /* FIXME: copied from src/main/valuepair.c */
			int i;
			regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];

			/*
			 *	Include substring matches.
			 */
			if (regcomp(&reg, this->rhs,
				    REG_EXTENDED) != 0) {
				/* FIXME: print error */
				return FALSE;
			}
			rad_assert(data != NULL);
			rcode = regexec(&reg, data,
					REQUEST_MAX_REGEX + 1,
					rxmatch, 0);
			rcode = (rcode == 0);
			regfree(&reg);

			/*
			 *	Add %{0}, %{1}, etc.
			 */
			for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
				char *p;
				char rxbuffer[256];

				/*
				 *	Didn't match: delete old
				 *	match, if it existed.
				 */
				if (!rcode ||
				    (rxmatch[i].rm_so == -1)) {
					p = request_data_get(state->request, state->request,
							     REQUEST_DATA_REGEX | i);
					if (p) {
						free(p);
						continue;
					}

					/*
					 *	No previous match
					 *	to delete, stop.
					 */
					break;
				}

				/*
				 *	Copy substring into buffer.
				 */
				memcpy(rxbuffer,
				       data + rxmatch[i].rm_so,
				       rxmatch[i].rm_eo - rxmatch[i].rm_so);
				rxbuffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';

				/*
				 *	Copy substring, and add it to
				 *	the request.
				 *
				 *	Note that we don't check
				 *	for out of memory, which is
				 *	the only error we can get...
				 */
				p = strdup(rxbuffer);
				request_data_add(state->request,
						 state->request,
						 REQUEST_DATA_REGEX | i,
						 p, free);
			}

		}
		break;

		case POLICY_LEX_RX_NOT_EQUALS:
			regcomp(&reg, this->rhs, REG_EXTENDED|REG_NOSUB);
			rad_assert(data != NULL);
			rcode = regexec(&reg, data,
					0, NULL, 0);
			rcode = (rcode != 0);
			regfree(&reg);
				break;
#endif /* HAVE_REGEX_H */
		default:
			rcode = FALSE;
			break;
		} /* switch over comparison operators */
		break;		/* default from first switch over compare */
	}

	if (this->sense) rcode = (rcode == FALSE); /* reverse sense of test */

	/*
	 *	No trailing &&, ||
	 */
	switch (this->child_condition) {
	default:
		return rcode;

	case POLICY_LEX_L_AND:
		if (!rcode) return rcode; /* FALSE && x == FALSE */
		break;

	case POLICY_LEX_L_OR:
		if (rcode) return rcode; /* TRUE && x == TRUE */
		break;
	}

	/*
	 *	Tail recursion.
	 */
	this = (const policy_condition_t *) this->child;
	goto redo;

	return 1;		/* should never reach here */
}
Example #6
0
File: help.c Project: Vortac/atheme
void help_display_as_subcmd(sourceinfo_t *si, service_t *service, const char *subcmd_of, const char *command, mowgli_patricia_t *list)
{
	command_t *c;
	FILE *help_file = NULL;
	char subname[BUFSIZE], buf[BUFSIZE];
	const char *langname = NULL;
	int ifnest, ifnest_false;


	char *ccommand = sstrdup(command);
	char *subcmd = strtok(ccommand, " ");
	subcmd = strtok(NULL, "");

	/* take the command through the hash table */
	if ((c = help_cmd_find(si, subcmd_of, ccommand, list)))
	{
		if (c->help.path)
		{
			if (*c->help.path == '/')
				help_file = fopen(c->help.path, "r");
			else
			{
				mowgli_strlcpy(subname, c->help.path, sizeof subname);
				if (nicksvs.no_nick_ownership && !strncmp(subname, "nickserv/", 9))
					memcpy(subname, "userserv", 8);
				if (si->smu != NULL)
				{
					langname = language_get_real_name(si->smu->language);
					if (langname && !strcmp(langname, "en"))
						langname = NULL;
				}
				if (langname != NULL)
				{
					snprintf(buf, sizeof buf, "%s/%s/%s", SHAREDIR "/help", langname, subname);
					help_file = fopen(buf, "r");
				}
				if (help_file == NULL)
				{
					snprintf(buf, sizeof buf, "%s/%s", SHAREDIR "/help", subname);
					help_file = fopen(buf, "r");
				}
			}

			if (!help_file)
			{
				command_fail(si, fault_nosuch_target, _("Could not get help file for \2%s\2."), command);
				return;
			}

			command_success_nodata(si, _("***** \2%s Help\2 *****"), service->nick);

			ifnest = ifnest_false = 0;
			while (fgets(buf, BUFSIZE, help_file))
			{
				strip(buf);

				replace(buf, sizeof(buf), "&nick&", service->disp);
				if (!strncmp(buf, "#if", 3))
				{
					if (ifnest_false > 0 || !evaluate_condition(si, buf + 3))
						ifnest_false++;
					ifnest++;
					continue;
				}
				else if (!strncmp(buf, "#endif", 6))
				{
					if (ifnest_false > 0)
						ifnest_false--;
					if (ifnest > 0)
						ifnest--;
					continue;
				}
				else if (!strncmp(buf, "#else", 5))
				{
					if (ifnest > 0 && ifnest_false <= 1)
						ifnest_false ^= 1;
					continue;
				}
				if (ifnest_false > 0)
					continue;

				if (buf[0])
					command_success_nodata(si, "%s", buf);
				else
					command_success_nodata(si, " ");
			}

			fclose(help_file);

			command_success_nodata(si, _("***** \2End of Help\2 *****"));
		}
		else if (c->help.func)
		{
			/* I removed the "***** Help" stuff from here because everything
			 * that uses a help function now calls help_display so they'll
			 * display on that and not show the message twice. --JD
			 */
			c->help.func(si, subcmd);
		}
		else
			no_help_available(si, subcmd_of, command);
	}
	free(ccommand);
}
Example #7
0
bool expr_handler::fold_alu_op3(alu_node& n) {

	if (n.src.size() < 3)
		return false;

	if (!sh.safe_math && (n.bc.op_ptr->flags & AF_M_ASSOC)) {
		if (fold_assoc(&n))
			return true;
		if (n.src.size() < 3)
			return fold_alu_op2(n);
	}

	value* v0 = n.src[0]->gvalue();
	value* v1 = n.src[1]->gvalue();
	value* v2 = n.src[2]->gvalue();

	/* LDS instructions look like op3 with no dst - don't fold. */
	if (!n.dst[0])
		return false;
	assert(v0 && v1 && v2 && n.dst[0]);

	bool isc0 = v0->is_const();
	bool isc1 = v1->is_const();
	bool isc2 = v2->is_const();

	literal dv, cv0, cv1, cv2;

	if (isc0) {
		cv0 = v0->get_const_value();
		apply_alu_src_mod(n.bc, 0, cv0);
	}

	if (isc1) {
		cv1 = v1->get_const_value();
		apply_alu_src_mod(n.bc, 1, cv1);
	}

	if (isc2) {
		cv2 = v2->get_const_value();
		apply_alu_src_mod(n.bc, 2, cv2);
	}

	unsigned flags = n.bc.op_ptr->flags;

	if (flags & AF_CMOV) {
		int src = 0;

		if (v1 == v2 && n.bc.src[1].neg == n.bc.src[2].neg) {
			// result doesn't depend on condition, convert to MOV
			src = 1;
		} else if (isc0) {
			// src0 is const, condition can be evaluated, convert to MOV
			bool cond = evaluate_condition(n.bc.op_ptr->flags & (AF_CC_MASK |
					AF_CMP_TYPE_MASK), cv0, literal(0));
			src = cond ? 1 : 2;
		}

		if (src) {
			// if src is selected, convert to MOV
			convert_to_mov(n, n.src[src], n.bc.src[src].neg);
			return fold_alu_op1(n);
		}
	}

	// handle (MULADD a, x, MUL (x, b)) => (MUL x, ADD (a, b))
	if (!sh.safe_math && (n.bc.op == ALU_OP3_MULADD ||
			n.bc.op == ALU_OP3_MULADD_IEEE)) {

		unsigned op = n.bc.op == ALU_OP3_MULADD_IEEE ?
				ALU_OP2_MUL_IEEE : ALU_OP2_MUL;

		if (!isc2 && v2->def && v2->def->is_alu_op(op)) {

			alu_node *md = static_cast<alu_node*>(v2->def);
			value *mv0 = md->src[0]->gvalue();
			value *mv1 = md->src[1]->gvalue();

			int es0 = -1, es1;

			if (v0 == mv0) {
				es0 = 0;
				es1 = 0;
			} else if (v0 == mv1) {
				es0 = 0;
				es1 = 1;
			} else if (v1 == mv0) {
				es0 = 1;
				es1 = 0;
			} else if (v1 == mv1) {
				es0 = 1;
				es1 = 1;
			}

			value *va0 = es0 == 0 ? v1 : v0;
			value *va1 = es1 == 0 ? mv1 : mv0;

			/* Don't fold if no equal multipliers were found.
			 * Also don#t fold if the operands of the to be created ADD are both
			 * relatively accessed with different AR values because that would
			 * create impossible code.
			 */
			if (es0 != -1 &&
			    (!va0->is_rel() || !va1->is_rel() ||
			     (va0->rel == va1->rel))) {

				alu_node *add = sh.create_alu();
				add->bc.set_op(ALU_OP2_ADD);

				add->dst.resize(1);
				add->src.resize(2);

				value *t = sh.create_temp_value();
				t->def = add;
				add->dst[0] = t;
				add->src[0] = va0;
				add->src[1] = va1;
				add->bc.src[0] = n.bc.src[!es0];
				add->bc.src[1] = md->bc.src[!es1];

				add->bc.src[1].neg ^= n.bc.src[2].neg ^
						(n.bc.src[es0].neg != md->bc.src[es1].neg);

				n.insert_before(add);
				vt.add_value(t);

				t = t->gvalue();

				if (es0 == 1) {
					n.src[0] = n.src[1];
					n.bc.src[0] = n.bc.src[1];
				}

				n.src[1] = t;
				memset(&n.bc.src[1], 0, sizeof(bc_alu_src));

				n.src.resize(2);

				n.bc.set_op(op);
				return fold_alu_op2(n);
			}
		}
	}

	if (!isc0 && !isc1 && !isc2)
		return false;

	if (isc0 && isc1 && isc2) {
		switch (n.bc.op) {
		case ALU_OP3_MULADD_IEEE:
		case ALU_OP3_MULADD: dv = cv0.f * cv1.f + cv2.f; break;

		// TODO

		default:
			return false;
		}
	} else {
		if (isc0 && isc1) {
			switch (n.bc.op) {
			case ALU_OP3_MULADD:
			case ALU_OP3_MULADD_IEEE:
				dv = cv0.f * cv1.f;
				n.bc.set_op(ALU_OP2_ADD);
				n.src[0] = sh.get_const_value(dv);
				memset(&n.bc.src[0], 0, sizeof(bc_alu_src));
				n.src[1] = n.src[2];
				n.bc.src[1] = n.bc.src[2];
				n.src.resize(2);
				return fold_alu_op2(n);
			}
		}

		if (n.bc.op == ALU_OP3_MULADD) {
			if ((isc0 && cv0 == literal(0)) || (isc1 && cv1 == literal(0))) {
				convert_to_mov(n, n.src[2], n.bc.src[2].neg,  n.bc.src[2].abs);
				return fold_alu_op1(n);
			}
		}

		if (n.bc.op == ALU_OP3_MULADD || n.bc.op == ALU_OP3_MULADD_IEEE) {
			unsigned op = n.bc.op == ALU_OP3_MULADD_IEEE ?
					ALU_OP2_MUL_IEEE : ALU_OP2_MUL;

			if (isc1 && v0 == v2) {
				cv1.f += (n.bc.src[2].neg != n.bc.src[0].neg ? -1.0f : 1.0f);
				n.src[1] = sh.get_const_value(cv1);
				n.bc.src[1].neg = 0;
				n.bc.src[1].abs = 0;
				n.bc.set_op(op);
				n.src.resize(2);
				return fold_alu_op2(n);
			} else if (isc0 && v1 == v2) {
				cv0.f += (n.bc.src[2].neg != n.bc.src[1].neg ? -1.0f : 1.0f);
				n.src[0] = sh.get_const_value(cv0);
				n.bc.src[0].neg = 0;
				n.bc.src[0].abs = 0;
				n.bc.set_op(op);
				n.src.resize(2);
				return fold_alu_op2(n);
			}
		}

		return false;
	}

	apply_alu_dst_mod(n.bc, dv);
	assign_source(n.dst[0], get_const(dv));
	return true;
}
Example #8
0
bool expr_handler::fold_setcc(alu_node &n) {

	value* v0 = n.src[0]->gvalue();
	value* v1 = n.src[1]->gvalue();

	assert(v0 && v1 && n.dst[0]);

	unsigned flags = n.bc.op_ptr->flags;
	unsigned cc = flags & AF_CC_MASK;
	unsigned cmp_type = flags & AF_CMP_TYPE_MASK;
	unsigned dst_type = flags & AF_DST_TYPE_MASK;

	bool cond_result;
	bool have_result = false;

	bool isc0 = v0->is_const();
	bool isc1 = v1->is_const();

	literal dv, cv0, cv1;

	if (isc0) {
		cv0 = v0->get_const_value();
		apply_alu_src_mod(n.bc, 0, cv0);
	}

	if (isc1) {
		cv1 = v1->get_const_value();
		apply_alu_src_mod(n.bc, 1, cv1);
	}

	if (isc0 && isc1) {
		cond_result = evaluate_condition(flags, cv0, cv1);
		have_result = true;
	} else if (isc1) {
		if (cmp_type == AF_FLOAT_CMP) {
			if (n.bc.src[0].abs && !n.bc.src[0].neg) {
				if (cv1.f < 0.0f && (cc == AF_CC_GT || cc == AF_CC_NE)) {
					cond_result = true;
					have_result = true;
				} else if (cv1.f <= 0.0f && cc == AF_CC_GE) {
					cond_result = true;
					have_result = true;
				}
			} else if (n.bc.src[0].abs && n.bc.src[0].neg) {
				if (cv1.f > 0.0f && (cc == AF_CC_GE || cc == AF_CC_E)) {
					cond_result = false;
					have_result = true;
				} else if (cv1.f >= 0.0f && cc == AF_CC_GT) {
					cond_result = false;
					have_result = true;
				}
			}
		} else if (cmp_type == AF_UINT_CMP && cv1.u == 0 && cc == AF_CC_GE) {
			cond_result = true;
			have_result = true;
		}
	} else if (isc0) {
		if (cmp_type == AF_FLOAT_CMP) {
			if (n.bc.src[1].abs && !n.bc.src[1].neg) {
				if (cv0.f <= 0.0f && cc == AF_CC_GT) {
					cond_result = false;
					have_result = true;
				} else if (cv0.f < 0.0f && (cc == AF_CC_GE || cc == AF_CC_E)) {
					cond_result = false;
					have_result = true;
				}
			} else if (n.bc.src[1].abs && n.bc.src[1].neg) {
				if (cv0.f >= 0.0f && cc == AF_CC_GE) {
					cond_result = true;
					have_result = true;
				} else if (cv0.f > 0.0f && (cc == AF_CC_GT || cc == AF_CC_NE)) {
					cond_result = true;
					have_result = true;
				}
			}
		} else if (cmp_type == AF_UINT_CMP && cv0.u == 0 && cc == AF_CC_GT) {
			cond_result = false;
			have_result = true;
		}
	} else if (v0 == v1) {
		bc_alu_src &s0 = n.bc.src[0], &s1 = n.bc.src[1];
		if (s0.abs == s1.abs && s0.neg == s1.neg && cmp_type != AF_FLOAT_CMP) {
			// NOTE can't handle float comparisons here because of NaNs
			cond_result = (cc == AF_CC_E || cc == AF_CC_GE);
			have_result = true;
		}
	}

	if (have_result) {
		literal result;

		if (cond_result)
			result = dst_type != AF_FLOAT_DST ?
					literal(0xFFFFFFFFu) : literal(1.0f);
		else
			result = literal(0);

		convert_to_mov(n, sh.get_const_value(result));
		return fold_alu_op1(n);
	}

	return false;
}