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; }
/* * 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;; }
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; }
/* * 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; }
/* * 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(®, this->rhs, REG_EXTENDED) != 0) { /* FIXME: print error */ return FALSE; } rad_assert(data != NULL); rcode = regexec(®, data, REQUEST_MAX_REGEX + 1, rxmatch, 0); rcode = (rcode == 0); regfree(®); /* * 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(®, this->rhs, REG_EXTENDED|REG_NOSUB); rad_assert(data != NULL); rcode = regexec(®, data, 0, NULL, 0); rcode = (rcode != 0); regfree(®); 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 */ }
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); }
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; }
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; }