/* Create either a zero matrix or an identity matrix. */ void matrix_create(enum nilop op) { decNumber x; int r, c, i, j; decimal64 *base; const decimal64 *diag, *off; getX(&x); base = matrix_decomp(&x, &r, &c); if (base != NULL) { off = get_const(OP_ZERO, 0)->s; if (op == OP_MAT_IDENT) { if (r != c) { err(ERR_MATRIX_DIM); return; } diag = get_const(OP_ONE, 0)->s; } else diag = off; for (i=0; i<r; i++) for (j=0; j<c; j++) *base++ = *((i==j)?diag:off); } }
/* Invert a matrix in situ. * Do this by calculating the LU decomposition and solving lots of systems * of linear equations. */ void matrix_inverse(enum nilop op) { decimal128 mat[MAX_SQUARE*MAX_SQUARE]; decNumber x[MAX_SQUARE]; unsigned char pivots[MAX_SQUARE]; int i, j, n; decimal64 *base; const decimal64 *b[MAX_SQUARE]; getX(x); n = matrix_lu_check(x, mat, &base); if (n == 0) return; i = LU_decomposition(mat, pivots, n); if (i == 0) { err(ERR_SINGULAR); return; } for (i=0; i<n; i++) { for (j=0; j<n; j++) b[j] = (i==j) ? (decimal64 *) get_const(OP_ONE, 0) : (decimal64 *) get_const(OP_ZERO, 0); matrix_pivoting_solve(mat, b, pivots, x, n); for (j=0; j<n; j++) packed_from_number(base + matrix_idx(j, i, n), x+j); } }
PUBLIC type range_type(tree lower, tree upper) { type p; check_type("range type", int_type, lower->t_type); check_type("range type", int_type, upper->t_type); p = alloc_type(); p->x_kind = RANGE; p->x_base = int_type; p->x_lo = atol(get_const(lower)); p->x_hi = atol(get_const(upper)); return p; }
bool expr_handler::fold(fetch_node& n) { unsigned chan = 0; for (vvec::iterator I = n.dst.begin(), E = n.dst.end(); I != E; ++I) { value* &v = *I; if (v) { if (n.bc.dst_sel[chan] == SEL_0) assign_source(*I, get_const(0.0f)); else if (n.bc.dst_sel[chan] == SEL_1) assign_source(*I, get_const(1.0f)); } ++chan; } return false; }
static void dump_constants(void) { char buf[100]; int i; for (i=0; i<NUM_CONSTS; i++) { decimal128ToString(&(get_const(i, 1)->d), buf); printf("\t%02d\t%s\n", i, buf); } }
virtual std::shared_ptr<TaskData> prepare_data(std::size_t n) override { auto data = std::make_shared<common::RandomData<item_type>>(n, '0', 'z'); auto space_idx = common::RandomData<int>(n/10, 0, n); auto d = data->get_mutable(); for (auto i : space_idx.get_const()) d.at(i) = ' '; d.at(d.size()-1) = '0'; I() << std::string(d.begin(), d.end()); return data; }
void set_aryLen(void) /* 配列サイズ設定 */ { tmpTb.aryLen = 0; if (token.kind != '[') return; /* 配列でない */ token = nextTkn(); if (token.kind == ']') { /* []である */ err_s("添字指定がない"); token = nextTkn(); tmpTb.aryLen = 1; return; /* 1だったことにする */ } get_const(NULL); /* 定数判定準備 */ expr_with_chk(0, ']'); /* 添字を取得 */ if (get_const(&(tmpTb.aryLen))) { /* 定数式なら */ if (tmpTb.aryLen <= 0) { tmpTb.aryLen = 1; err_s("不正な添字"); /* 1だったことにする */ } } else { err_s("配列幅指定が整数定数式でない"); } if (token.kind == '[') { err_ss("多次元配列は宣言できない", token.text); } }
static void rarg_values(const opcode c, int l) { char bf[100]; if (isRARG(c)) { const unsigned int cmd = RARG_CMD(c); const unsigned int idx = c & 0x7f; if (cmd == RARG_CONV) { while (l-- > 0) putchar(' '); printf("%c %s", (idx & 1)?'*':'/', decimal64ToString(&CONSTANT_CONV(idx/2), bf)); } else if (cmd == RARG_CONST || cmd == RARG_CONST_CMPLX) { while (l-- > 0) putchar(' '); printf("%s", decimal64ToString((decimal64 *) get_const(c & 0x7f, 0), bf)); } } }
/* * add a string to the constant pool * handle underscore * */ int add_buffer (char *p, char c, int is_address) { SYMBOL *s = 0; /* underscore */ if (alpha(*p)) { if (!is_address) { s = findglb(p); if (!s) { error("undefined global"); return (0); } /* Unless preceded by an address operator, we need to get the value, and it better be constant... */ p = get_const(s); if (!p) { error("non-constant initializer"); return (0); } } else if (c != '(') { /* If we want the address, we need an underscore prefix. */ if (const_data_idx < MAX_CONST_DATA) const_data[const_data_idx++] = '_'; } } /* string */ while (*p) { if (const_data_idx < MAX_CONST_DATA) const_data[const_data_idx++] = *p; p++; } /* tell the caller if there were any addresses involved */ return ((s && s->ident == POINTER) || is_address); }
/* この関数内のラベル処理(飛先処理)の明快さのために以下のマクロを使用する */ #define UPLABEL(pos) pos=nextCodeCt() /* 上ジャンプ用ラベル機能 */ #define JMP_UP(pos) gencode2(JMP,pos) /* JMPでUPLABELへ */ #define JPT_UP(pos) gencode2(JPT,pos) /* JPTでUPLABELへ */ #define JMP_DOWN(pos) pos=gencode2(JMP,0) /* JMPでDWNLABELへ */ #define JPF_DOWN(pos) pos=gencode2(JPF,0) /* JPFでDWNLABELへ */ #define DWNLABEL(pos) backPatch(pos,nextCodeCt()) /* 下ジャンプ用ラベル機能 */ void statement(void) /* 文の処理 */ { TknKind kd; SymTbl *tp; DtType ret_typ = fncPt->dtTyp; int i, val; int LB_TOP, LB_EXP2, LB_EXP3, LB_BODY, LB_ELSE, LB_END, LB_TBL; kd = token.kind; if (kd==While || kd==Do || kd==Switch) continue_break_begin(kd); switch (kd) { case Break: if (loopNest_ct == 0) err_s("不正なbreak"); else { gencode2(JMP, NO_FIX_BREAK_ADRS); /* 該当末尾位置へ */ loopNest[loopNest_ct].break_flg = TRUE; /* breakありを記憶 */ } token = chk_nextTkn(nextTkn(), ';'); /* ; のはず */ break; case Continue: gencode2(JMP, get_loopTop()); /* ループ開始行へジャンプ */ token = chk_nextTkn(nextTkn(), ';'); /* ; のはず */ break; case Case: token = nextTkn(); get_const(NULL); /* 定数判定準備 */ expr_with_chk(0, ':'); /* [式]の処理 */ if (!get_const(&val)) err_s("case式が定数式でない"); else if (swchNest_ct == 0) err_s("対応するswitch文がない"); else { for (i=swchNest[swchNest_ct].startCaseList; i<=caseList_ct; i++) { if (caseList[i].value == val) { err_s("case式の値が重複している"); break; } } incVar(&caseList_ct, CASE_SIZ, "case句が%d個を超えました。"); caseList[caseList_ct].value = val; /* case値設定 */ caseList[caseList_ct].adrs = nextCodeCt(); /* 対応番地設定 */ } statement(); /* 文の処理 */ break; case Default: if (swchNest_ct == 0) err_s("対応するswitch文がない"); else if (swchNest[swchNest_ct].def_adrs != -1) err_s("defaultが重複している"); else swchNest[swchNest_ct].def_adrs = nextCodeCt(); /* 番地設定 */ token = chk_nextTkn(nextTkn(), ':'); /* : のはず */ statement(); /* 文の処理 */ break; case For: /*[式1]*/ token = chk_nextTkn(nextTkn(), '('); /* ( のはず */ if (token.kind == ';') token = nextTkn(); /* 式1なし */ else { expr_with_chk(0, ';'); /* [式1]の処理 */ remove_val(); /* 式値不要 */ } /*[式2]*/ UPLABEL(LB_EXP2); /* ←┐ */ if (token.kind == ';') { /* │式2なし */ gencode2(LDI, 1); /* │真(1)にする */ token = nextTkn(); /* │ */ } else { /* │ */ expr_with_chk(0, ';'); /* │[式2]の処理 */ } /* │ */ JPF_DOWN(LB_END); /* ─┼┐ false時 */ JMP_DOWN(LB_BODY); /* ─┼┼┐true時 */ /* │││ */ /*[式3]*/ /* │││ */ continue_break_begin(kd); /* │││ */ UPLABEL(LB_EXP3); /* ←┼┼┼┐ */ if (token.kind == ')') /* ││││ */ token = nextTkn(); /* ││││式3なし */ else { /* ││││ */ expr_with_chk(0, ')'); /* ││││[式3]の処理 */ remove_val(); /* ││││式値不要 */ } /* ││││ */ JMP_UP(LB_EXP2); /* ─┘│││ */ /* │││ */ /*[本体]*/ /* │││ */ DWNLABEL(LB_BODY); /* ←─┼┘│ */ statement(); /* │ │[文]の処理 */ JMP_UP(LB_EXP3); /* ──┼─┘繰り返し */ /* │ */ /*[末尾]*/ /* │ */ DWNLABEL(LB_END); /* ←─┘終端 */ break; case If: token = nextTkn(); expr_with_chk('(', ')'); /* [式]の処理 */ JPF_DOWN(LB_ELSE); /* ─┐ false時 */ statement(); /* │ [文1]の処理 */ if (token.kind != Else) { /* │ */ DWNLABEL(LB_ELSE); /* ←┘elseない時の終端 */ break; /* │ */ } /* │elseある時 */ JMP_DOWN(LB_END); /* ─┼┐ */ DWNLABEL(LB_ELSE); /* ←┘│ */ token = nextTkn(); /* │ */ statement(); /* │[文2]の処理 */ DWNLABEL(LB_END); /* ←─┘ */ break; case While: token = nextTkn(); UPLABEL(LB_TOP); /* ←┐ */ expr_with_chk('(', ')'); /* │ [式]の処理 */ JPF_DOWN(LB_END); /* ─┼┐false時 */ statement(); /* ││[文]の処理 */ JMP_UP(LB_TOP); /* ─┘│繰り返し */ DWNLABEL(LB_END); /* ←─┘ */ break; case Do: token = nextTkn(); UPLABEL(LB_TOP); /* ←┐ */ statement(); /* │[文]の処理 */ if (token.kind == While) { /* │ */ token = nextTkn(); /* │ */ expr_with_chk('(', ')'); /* │[式]の処理 */ token = chk_nextTkn(token, ';'); /* │; のはず */ JPT_UP(LB_TOP); /* ─┘true時 */ } else { err_s("do終端のwhileがない"); } break; case Switch: token = nextTkn(); expr_with_chk('(', ')'); /* [式]の処理 */ JMP_DOWN(LB_TBL); /* ─┐ テーブル処理へ */ swch_begin(); /* │ */ statement(); /* case,default文の処理. */ JMP_DOWN(LB_END); /* ─┼┐末尾へ */ DWNLABEL(LB_TBL); /* ←┘│ */ swch_end(); /* │テーブル処理 */ DWNLABEL(LB_END); /* ←─┘ */ break; case Return: token = nextTkn(); if (token.kind == ';') { /* 戻値なし */ if (ret_typ != VOID_T) err_s("return文に戻り値がない"); } else { /* 戻値あり */ expression(); /* 戻値作成 */ if (ret_typ == VOID_T) err_s("void型関数に値を返すreturn文がある"); } gencode2(JMP, NO_FIX_RET_ADRS); /* 関数出口処理へ */ token = chk_nextTkn(token, ';'); /* ; のはず */ break; case Printf: case Exit: /* void型組込関数 */ sys_fncCall(kd); token = chk_nextTkn(token, ';'); /* printf() + b; を防止 */ break; case Input: /* 非void型組込関数 */ expr_with_chk(0, ';'); /* 通常の式解析 */ remove_val(); /* 式値不要 */ break; case Incre: case Decre: /* ++var --var */ expr_with_chk(0, ';'); remove_val(); /* 式値不要 */ break; case Ident: /* 識別子(関数か変数) */ tp = search(token.text); /* 記号表位置 */ if ((tp->nmKind==fncId || tp->nmKind==protId) && tp->dtTyp==VOID_T) { fncCall(tp); /* void型関数はここで処理 */ token = chk_nextTkn(token, ';'); /* ; のはず */ } else { expr_with_chk(0, ';'); /* 通常の式解析 */ remove_val(); /* 式値不要 */ } break; case Lbrace: /* 複合文{} */ block(0); /* 0:非関数ブロック */ break; case Semicolon: /* 空文,forの実行文等で出現 */ token = nextTkn(); break; case EofTkn: /* 最後の } を忘れた場合などに発生 */ err_s("意図しない終了。'}'不足? "); exit(1); default: err_ss("不正な記述", token.text); token = nextTkn(); } if (kd==For || kd==While || kd==Do || kd==Switch) continue_break_end(); }
void comp_fbcc_opp (uae_u32 opcode) { uae_u32 start_68k_offset=m68k_pc_offset; uae_u32 off, v1, v2; int cc; if (!currprefs.compfpu) { FAIL(1); return; } if (opcode & 0x20) { /* only cc from 00 to 1f are defined */ FAIL(1); return; } if (!(opcode & 0x40)) { off = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); } else { off = comp_get_ilong((m68k_pc_offset+=4)-4); } mov_l_ri(S1,(uae_u32) (comp_pc_p+off-(m68k_pc_offset-start_68k_offset))); mov_l_ri(PC_P,(uae_u32)comp_pc_p); /* Now they are both constant. Might as well fold in m68k_pc_offset */ add_l_ri(S1,m68k_pc_offset); add_l_ri(PC_P,m68k_pc_offset); m68k_pc_offset=0; /* according to fpp.c, the 0x10 bit is ignored (it handles exception handling, which we don't do, anyway ;-) */ cc = opcode & 0x0f; v1 = get_const(PC_P); v2 = get_const(S1); fflags_into_flags(S2); // mov_l_mi((uae_u32)&foink3,cc); switch(cc) { case 0: break; /* jump never */ case 1: mov_l_rr(S2,PC_P); cmov_l_rr(PC_P,S1,4); cmov_l_rr(PC_P,S2,10); break; case 2: register_branch(v1,v2,7); break; case 3: register_branch(v1,v2,3); break; case 4: mov_l_rr(S2,PC_P); cmov_l_rr(PC_P,S1,2); cmov_l_rr(PC_P,S2,10); break; case 5: mov_l_rr(S2,PC_P); cmov_l_rr(PC_P,S1,6); cmov_l_rr(PC_P,S2,10); break; case 6: register_branch(v1,v2,5); break; case 7: register_branch(v1,v2,11); break; case 8: register_branch(v1,v2,10); break; case 9: register_branch(v1,v2,4); break; case 10: cmov_l_rr(PC_P,S1,10); cmov_l_rr(PC_P,S1,7); break; case 11: cmov_l_rr(PC_P,S1,4); cmov_l_rr(PC_P,S1,3); break; case 12: register_branch(v1,v2,2); break; case 13: register_branch(v1,v2,6); break; case 14: cmov_l_rr(PC_P,S1,5); cmov_l_rr(PC_P,S1,10); break; case 15: mov_l_rr(PC_P,S1); break; } }
Object* Module::get_const(STATE, const char* sym) { return get_const(state, state->symbol(sym)); }
Object* Module::get_const(STATE, Symbol* sym) { bool found; return get_const(state, sym, &found); }
Object* Module::get_const(STATE, std::string sym) { return get_const(state, state->symbol(sym)); }
bool expr_handler::fold_alu_op1(alu_node& n) { assert(!n.src.empty()); if (n.src.empty()) return false; /* don't fold LDS instructions */ if (n.bc.op_ptr->flags & AF_LDS) return false; value* v0 = n.src[0]->gvalue(); if (v0->is_lds_oq() || v0->is_lds_access()) return false; assert(v0 && n.dst[0]); if (!v0->is_const()) { // handle (MOV -(MOV -x)) => (MOV x) if (n.bc.op == ALU_OP1_MOV && n.bc.src[0].neg && !n.bc.src[1].abs && v0->def && v0->def->is_alu_op(ALU_OP1_MOV)) { alu_node *sd = static_cast<alu_node*>(v0->def); if (!sd->bc.clamp && !sd->bc.omod && !sd->bc.src[0].abs && sd->bc.src[0].neg) { n.src[0] = sd->src[0]; n.bc.src[0].neg = 0; v0 = n.src[0]->gvalue(); } } if ((n.bc.op == ALU_OP1_MOV || n.bc.op == ALU_OP1_MOVA_INT || n.bc.op == ALU_OP1_MOVA_GPR_INT) && n.bc.clamp == 0 && n.bc.omod == 0 && n.bc.src[0].abs == 0 && n.bc.src[0].neg == 0 && n.src.size() == 1 /* RIM/SIM can be appended as additional values */ && n.dst[0]->no_reladdr_conflict_with(v0)) { assign_source(n.dst[0], v0); return true; } return false; } literal dv, cv = v0->get_const_value(); apply_alu_src_mod(n.bc, 0, cv); switch (n.bc.op) { case ALU_OP1_CEIL: dv = ceil(cv.f); break; case ALU_OP1_COS: dv = cos(cv.f * 2.0f * M_PI); break; case ALU_OP1_EXP_IEEE: dv = exp2(cv.f); break; case ALU_OP1_FLOOR: dv = floor(cv.f); break; case ALU_OP1_FLT_TO_INT: dv = (int)cv.f; break; // FIXME: round modes ???? case ALU_OP1_FLT_TO_INT_FLOOR: dv = (int32_t)floor(cv.f); break; case ALU_OP1_FLT_TO_INT_RPI: dv = (int32_t)floor(cv.f + 0.5f); break; case ALU_OP1_FLT_TO_INT_TRUNC: dv = (int32_t)trunc(cv.f); break; case ALU_OP1_FLT_TO_UINT: dv = (uint32_t)cv.f; break; case ALU_OP1_FRACT: dv = cv.f - floor(cv.f); break; case ALU_OP1_INT_TO_FLT: dv = (float)cv.i; break; case ALU_OP1_LOG_CLAMPED: case ALU_OP1_LOG_IEEE: if (cv.f != 0.0f) dv = log2(cv.f); else // don't fold to NAN, let the GPU handle it for now // (prevents degenerate LIT tests from failing) return false; break; case ALU_OP1_MOV: dv = cv; break; case ALU_OP1_MOVA_INT: dv = cv; break; // FIXME ??? // case ALU_OP1_MOVA_FLOOR: dv = (int32_t)floor(cv.f); break; // case ALU_OP1_MOVA_GPR_INT: case ALU_OP1_NOT_INT: dv = ~cv.i; break; case ALU_OP1_PRED_SET_INV: dv = cv.f == 0.0f ? 1.0f : (cv.f == 1.0f ? 0.0f : cv.f); break; case ALU_OP1_PRED_SET_RESTORE: dv = cv; break; case ALU_OP1_RECIPSQRT_CLAMPED: case ALU_OP1_RECIPSQRT_FF: case ALU_OP1_RECIPSQRT_IEEE: dv = 1.0f / sqrt(cv.f); break; case ALU_OP1_RECIP_CLAMPED: case ALU_OP1_RECIP_FF: case ALU_OP1_RECIP_IEEE: dv = 1.0f / cv.f; break; // case ALU_OP1_RECIP_INT: case ALU_OP1_RECIP_UINT: dv.u = (1ull << 32) / cv.u; break; // case ALU_OP1_RNDNE: dv = floor(cv.f + 0.5f); break; case ALU_OP1_SIN: dv = sin(cv.f * 2.0f * M_PI); break; case ALU_OP1_SQRT_IEEE: dv = sqrt(cv.f); break; case ALU_OP1_TRUNC: dv = trunc(cv.f); break; default: return false; } apply_alu_dst_mod(n.bc, dv); assign_source(n.dst[0], get_const(dv)); return true; }
Object* Module::get_const(STATE, Symbol* sym) { ConstantMissingReason reason; return get_const(state, sym, G(sym_private), &reason); }
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; }
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; }
void get_constant_pool(Register reg) { get_const(reg); movptr(reg, Address(reg, constMethodOopDesc::constants_offset())); }