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; }
// fold the chain of associative ops, e.g. (ADD 2, (ADD x, 3)) => (ADD x, 5) bool expr_handler::fold_assoc(alu_node *n) { alu_node *a = n; literal cr; int last_arg = -3; unsigned op = n->bc.op; bool allow_neg = false, cur_neg = false; bool distribute_neg = false; switch(op) { case ALU_OP2_ADD: distribute_neg = true; allow_neg = true; break; case ALU_OP2_MUL: case ALU_OP2_MUL_IEEE: allow_neg = true; break; case ALU_OP3_MULADD: allow_neg = true; op = ALU_OP2_MUL; break; case ALU_OP3_MULADD_IEEE: allow_neg = true; op = ALU_OP2_MUL_IEEE; break; default: if (n->bc.op_ptr->src_count != 2) return false; } // check if we can evaluate the op if (!eval_const_op(op, cr, literal(0), literal(0))) return false; while (true) { value *v0 = a->src[0]->gvalue(); value *v1 = a->src[1]->gvalue(); last_arg = -2; if (v1->is_const()) { literal arg = v1->get_const_value(); apply_alu_src_mod(a->bc, 1, arg); if (cur_neg && distribute_neg) arg.f = -arg.f; if (a == n) cr = arg; else eval_const_op(op, cr, cr, arg); if (v0->def) { alu_node *d0 = static_cast<alu_node*>(v0->def); if ((d0->is_alu_op(op) || (op == ALU_OP2_MUL_IEEE && d0->is_alu_op(ALU_OP2_MUL))) && !d0->bc.omod && !d0->bc.clamp && !a->bc.src[0].abs && (!a->bc.src[0].neg || allow_neg)) { cur_neg ^= a->bc.src[0].neg; a = d0; continue; } } last_arg = 0; } if (v0->is_const()) { literal arg = v0->get_const_value(); apply_alu_src_mod(a->bc, 0, arg); if (cur_neg && distribute_neg) arg.f = -arg.f; if (last_arg == 0) { eval_const_op(op, cr, cr, arg); last_arg = -1; break; } if (a == n) cr = arg; else eval_const_op(op, cr, cr, arg); if (v1->def) { alu_node *d1 = static_cast<alu_node*>(v1->def); if ((d1->is_alu_op(op) || (op == ALU_OP2_MUL_IEEE && d1->is_alu_op(ALU_OP2_MUL))) && !d1->bc.omod && !d1->bc.clamp && !a->bc.src[1].abs && (!a->bc.src[1].neg || allow_neg)) { cur_neg ^= a->bc.src[1].neg; a = d1; continue; } } last_arg = 1; } break; }; if (last_arg == -1) { // result is const apply_alu_dst_mod(n->bc, cr); if (n->bc.op == op) { convert_to_mov(*n, sh.get_const_value(cr)); fold_alu_op1(*n); return true; } else { // MULADD => ADD n->src[0] = n->src[2]; n->bc.src[0] = n->bc.src[2]; n->src[1] = sh.get_const_value(cr); memset(&n->bc.src[1], 0, sizeof(bc_alu_src)); n->src.resize(2); n->bc.set_op(ALU_OP2_ADD); } } else if (last_arg >= 0) { n->src[0] = a->src[last_arg]; n->bc.src[0] = a->bc.src[last_arg]; n->bc.src[0].neg ^= cur_neg; n->src[1] = sh.get_const_value(cr); memset(&n->bc.src[1], 0, sizeof(bc_alu_src)); } return false; }
bool expr_handler::fold_alu_op2(alu_node& n) { if (n.src.size() < 2) return false; unsigned flags = n.bc.op_ptr->flags; if (flags & AF_SET) { return fold_setcc(n); } if (!sh.safe_math && (flags & AF_M_ASSOC)) { if (fold_assoc(&n)) return true; } value* v0 = n.src[0]->gvalue(); value* v1 = n.src[1]->gvalue(); assert(v0 && v1); // handle some operations with equal args, e.g. x + x => x * 2 if (v0 == v1) { if (n.bc.src[0].neg == n.bc.src[1].neg && n.bc.src[0].abs == n.bc.src[1].abs) { switch (n.bc.op) { case ALU_OP2_MIN: // (MIN x, x) => (MOV x) case ALU_OP2_MIN_DX10: case ALU_OP2_MAX: case ALU_OP2_MAX_DX10: convert_to_mov(n, v0, n.bc.src[0].neg, n.bc.src[0].abs); return fold_alu_op1(n); case ALU_OP2_ADD: // (ADD x, x) => (MUL x, 2) if (!sh.safe_math) { n.src[1] = sh.get_const_value(2.0f); memset(&n.bc.src[1], 0, sizeof(bc_alu_src)); n.bc.set_op(ALU_OP2_MUL); return fold_alu_op2(n); } break; } } if (n.bc.src[0].neg != n.bc.src[1].neg && n.bc.src[0].abs == n.bc.src[1].abs) { switch (n.bc.op) { case ALU_OP2_ADD: // (ADD x, -x) => (MOV 0) if (!sh.safe_math) { convert_to_mov(n, sh.get_const_value(literal(0))); return fold_alu_op1(n); } break; } } } if (n.bc.op == ALU_OP2_ADD) { if (fold_mul_add(&n)) return true; } bool isc0 = v0->is_const(); bool isc1 = v1->is_const(); if (!isc0 && !isc1) return false; 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) { if (!eval_const_op(n.bc.op, dv, cv0, cv1)) return false; } else { // one source is const if (isc0 && cv0 == literal(0)) { switch (n.bc.op) { case ALU_OP2_ADD: case ALU_OP2_ADD_INT: case ALU_OP2_MAX_UINT: case ALU_OP2_OR_INT: case ALU_OP2_XOR_INT: convert_to_mov(n, n.src[1], n.bc.src[1].neg, n.bc.src[1].abs); return fold_alu_op1(n); case ALU_OP2_AND_INT: case ALU_OP2_ASHR_INT: case ALU_OP2_LSHL_INT: case ALU_OP2_LSHR_INT: case ALU_OP2_MIN_UINT: case ALU_OP2_MUL: case ALU_OP2_MULHI_UINT: case ALU_OP2_MULLO_UINT: convert_to_mov(n, sh.get_const_value(literal(0))); return fold_alu_op1(n); } } else if (isc1 && cv1 == literal(0)) { switch (n.bc.op) { case ALU_OP2_ADD: case ALU_OP2_ADD_INT: case ALU_OP2_ASHR_INT: case ALU_OP2_LSHL_INT: case ALU_OP2_LSHR_INT: case ALU_OP2_MAX_UINT: case ALU_OP2_OR_INT: case ALU_OP2_SUB_INT: case ALU_OP2_XOR_INT: convert_to_mov(n, n.src[0], n.bc.src[0].neg, n.bc.src[0].abs); return fold_alu_op1(n); case ALU_OP2_AND_INT: case ALU_OP2_MIN_UINT: case ALU_OP2_MUL: case ALU_OP2_MULHI_UINT: case ALU_OP2_MULLO_UINT: convert_to_mov(n, sh.get_const_value(literal(0))); return fold_alu_op1(n); } } else if (isc0 && cv0 == literal(1.0f)) { switch (n.bc.op) { case ALU_OP2_MUL: case ALU_OP2_MUL_IEEE: convert_to_mov(n, n.src[1], n.bc.src[1].neg, n.bc.src[1].abs); return fold_alu_op1(n); } } else if (isc1 && cv1 == literal(1.0f)) { switch (n.bc.op) { case ALU_OP2_MUL: case ALU_OP2_MUL_IEEE: convert_to_mov(n, n.src[0], n.bc.src[0].neg, n.bc.src[0].abs); return fold_alu_op1(n); } } return false; } apply_alu_dst_mod(n.bc, dv); assign_source(n.dst[0], get_const(dv)); return true; }
static void edit_float( const dsc* desc, pics* picture, TEXT** output) { /************************************** * * e d i t _ f l o a t * ************************************** * * Functional description * Edit data from a descriptor through an edit string to a running * output pointer. * **************************************/ TEXT temp[512]; USHORT l, width, decimal_digits, w_digits, f_digits; double number = MOVQ_get_double(desc); const bool negative = (number < 0); if (negative) number = -number; // If exponents are explicitly requested (E-format edit_string), generate them. // Otherwise, the rules are: if the number in f-format will fit into the allotted // space, print it in f-format; otherwise print it in e-format. // (G-format is untrustworthy.) if (isnan(number)) sprintf(temp, "NaN"); else if (isinf(number)) sprintf(temp, "Infinity"); else if (picture->pic_exponents) { width = picture->pic_print_length - picture->pic_floats - picture->pic_literals; decimal_digits = picture->pic_fractions; sprintf(temp, "%*.*e", width, decimal_digits, number); } else if (number == 0) sprintf(temp, "%.0f", number); else { width = picture->pic_float_digits - 1 + picture->pic_floats; f_digits = (width > 2) ? width - 2 : 0; sprintf(temp, "%.*f", f_digits, number); w_digits = strlen(temp); if (f_digits) { TEXT* p = temp + w_digits; // find the end w_digits = w_digits - (f_digits + 1); while (*--p == '0') --f_digits; if (*p != '.') ++p; *p = 0; // move the end } if ((w_digits > width) || (!f_digits && w_digits == 1 && temp[0] == '0')) { // if the number doesn't fit in the default window, revert // to exponential notation; displaying the maximum number of // mantissa digits. if (number < 1e100) decimal_digits = (width > 6) ? width - 6 : 0; else decimal_digits = (width > 7) ? width - 7 : 0; sprintf(temp, "%.*e", decimal_digits, number); } } TEXT* p = temp; picture->pic_pointer = picture->pic_string; picture->pic_count = 0; TEXT* out = *output; for (l = picture->pic_length - picture->pic_print_length; l > 0; --l) *out++ = ' '; bool is_signed = false; for (;;) { const TEXT e = generate(picture); TEXT c = e; if (!c || c == '?') break; c = UPPER(c); switch (c) { case 'G': if (!is_signed) { if (negative) *out++ = '-'; else *out++ = ' '; is_signed = true; } else if (*p) *out++ = *p++; break; case 'B': *out++ = ' '; break; case '"': case '\'': case '\\': literal(picture, c, &out); break; case '9': case 'Z': { if (!(*p) || *p > '9' || *p < '0') break; TEXT d = *p++; if (c == '9' && d == ' ') d = '0'; else if (c == 'Z' && d == '0') d = ' '; *out++ = d; } break; case '.': *out++ = (*p == c) ? *p++ : c; break; case 'E': if (!*p) break; *out++ = e; if (UPPER(*p) == c) ++p; break; case '+': case '-': if (!*p) break; if (*p != '+' && *p != '-') { if (is_signed) *out++ = c; else if (c == '-' && !negative) *out++ = ' '; else if (c == '+' && negative) *out++ = '-'; else *out++ = c; is_signed = true; } else if (*p == '-' || c == '+') *out++ = *p++; else { *out++ = ' '; p++; } break; default: *out++ = c; break; } } *output = out; }
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; }
static void edit_alpha(const dsc* desc, pics* picture, TEXT** output, USHORT max_length) { /************************************** * * e d i t _ a l p h a * ************************************** * * Functional description * Edit data from a descriptor through an edit string to a running * output pointer. * **************************************/ Firebird::VaryStr<512> temp; const TEXT* p = NULL; const USHORT l = MOVQ_get_string(desc, &p, &temp, sizeof(temp)); const TEXT* const end = p + l; picture->pic_pointer = picture->pic_string; picture->pic_count = 0; TEXT* out = *output; while (p < end) { if ((out - *output) >= max_length) break; TEXT c = generate(picture); if (!c || c == '?') break; c = UPPER(c); switch (c) { case 'X': *out++ = *p++; break; case 'A': if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')) *out++ = *p++; else IBERROR(69); // Msg 69 conversion error break; case 'B': *out++ = ' '; break; case '"': case '\'': case '\\': literal(picture, c, &out); break; default: *out++ = c; break; } } *output = out; }
static void edit_date( const dsc* desc, pics* picture, TEXT** output) { /************************************** * * e d i t _ d a t e * ************************************** * * Functional description * Edit data from a descriptor through an edit string to a running * output pointer. * **************************************/ SLONG date[2]; DSC temp_desc; TEXT d, temp[256]; temp_desc.dsc_dtype = dtype_timestamp; temp_desc.dsc_scale = 0; temp_desc.dsc_sub_type = 0; temp_desc.dsc_length = sizeof(date); temp_desc.dsc_address = (UCHAR*) date; QLI_validate_desc(temp_desc); MOVQ_move(desc, &temp_desc); tm times; isc_decode_date((ISC_QUAD*) date, ×); TEXT* p = temp; const TEXT* nmonth = p; p = cvt_to_ascii((SLONG) times.tm_mon + 1, p, picture->pic_nmonths); const TEXT* day = p; p = cvt_to_ascii((SLONG) times.tm_mday, p, picture->pic_days); const TEXT* year = p; p = cvt_to_ascii((SLONG) times.tm_year + 1900, p, picture->pic_years); const TEXT* julians = p; p = cvt_to_ascii((SLONG) times.tm_yday + 1, p, picture->pic_julians); const TEXT* meridian = ""; if (picture->pic_meridian) { if (times.tm_hour >= 12) { meridian = "PM"; if (times.tm_hour > 12) times.tm_hour -= 12; } else meridian = "AM"; } const SLONG seconds = date[1] % (60 * PRECISION); TEXT* hours = p; p = cvt_to_ascii((SLONG) times.tm_hour, p, picture->pic_hours); p = cvt_to_ascii((SLONG) times.tm_min, --p, picture->pic_minutes); p = cvt_to_ascii((SLONG) seconds, --p, 6); if (*hours == '0') *hours = ' '; SLONG rel_day = (date[0] + 3) % 7; if (rel_day < 0) rel_day += 7; const TEXT* weekday = alpha_weekdays[rel_day]; const TEXT* month = alpha_months[times.tm_mon]; picture->pic_pointer = picture->pic_string; picture->pic_count = 0; TEXT* out = *output; bool sig_day = false; bool blank = true; for (;;) { TEXT c = generate(picture); if (!c || c == '?') break; c = UPPER(c); switch (c) { case 'Y': *out++ = *year++; break; case 'M': if (*month) *out++ = *month++; break; case 'N': *out++ = *nmonth++; break; case 'D': d = *day++; if (!sig_day && d == '0' && blank) *out++ = ' '; else { sig_day = true; *out++ = d; } break; case 'J': if (*julians) *out++ = *julians++; break; case 'W': if (*weekday) *out++ = *weekday++; break; case 'B': *out++ = ' '; break; case 'P': if (*meridian) *out++ = *meridian++; break; case 'T': if (*hours) *out++ = *hours++; break; case '"': case '\'': case '\\': literal(picture, c, &out); break; default: *out++ = c; break; } if (c != 'B') blank = false; } *output = out; }
oop protection_domain() { return literal(); }
symbolOop symbol() const { return (symbolOop) literal(); }
bool equals(symbolOop class_name, oop class_loader) const { klassOop klass = (klassOop)literal(); return (instanceKlass::cast(klass)->name() == class_name && _loader == class_loader); }
klassOop klass() const { return (klassOop)literal(); }
// Simple accessors, used only by SystemDictionary Symbol* klassname() const { return literal(); }