📄 sh.c
字号:
if (TARGET_SH2) { /* We have a mul insn, so we can never take more than the mul and the read of the mac reg, but count more because of the latency and extra reg usage. */ if (TARGET_SMALLCODE) return 2; return 3; } /* If we're aiming at small code, then just count the number of insns in a multiply call sequence. */ if (TARGET_SMALLCODE) return 5; /* Otherwise count all the insns in the routine we'd be calling too. */ return 20;}/* Code to expand a shift. */voidgen_ashift (type, n, reg) int type; int n; rtx reg;{ /* Negative values here come from the shift_amounts array. */ if (n < 0) { if (type == ASHIFT) type = LSHIFTRT; else type = ASHIFT; n = -n; } switch (type) { case ASHIFTRT: emit_insn (gen_ashrsi3_k (reg, reg, GEN_INT (n))); break; case LSHIFTRT: if (n == 1) emit_insn (gen_lshrsi3_m (reg, reg, GEN_INT (n))); else emit_insn (gen_lshrsi3_k (reg, reg, GEN_INT (n))); break; case ASHIFT: emit_insn (gen_ashlsi3_std (reg, reg, GEN_INT (n))); break; }}/* Same for HImode */voidgen_ashift_hi (type, n, reg) int type; int n; rtx reg;{ /* Negative values here come from the shift_amounts array. */ if (n < 0) { if (type == ASHIFT) type = LSHIFTRT; else type = ASHIFT; n = -n; } switch (type) { case ASHIFTRT: case LSHIFTRT: /* We don't have HImode right shift operations because using the ordinary 32 bit shift instructions for that doesn't generate proper zero/sign extension. gen_ashift_hi is only called in contexts where we know that the sign extension works out correctly. */ { int offset = 0; if (GET_CODE (reg) == SUBREG) { offset = SUBREG_BYTE (reg); reg = SUBREG_REG (reg); } gen_ashift (type, n, gen_rtx_SUBREG (SImode, reg, offset)); break; } case ASHIFT: emit_insn (gen_ashlhi3_k (reg, reg, GEN_INT (n))); break; }}/* Output RTL to split a constant shift into its component SH constant shift instructions. */ voidgen_shifty_op (code, operands) int code; rtx *operands;{ int value = INTVAL (operands[2]); int max, i; /* Truncate the shift count in case it is out of bounds. */ value = value & 0x1f; if (value == 31) { if (code == LSHIFTRT) { emit_insn (gen_rotlsi3_1 (operands[0], operands[0])); emit_insn (gen_movt (operands[0])); return; } else if (code == ASHIFT) { /* There is a two instruction sequence for 31 bit left shifts, but it requires r0. */ if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 0) { emit_insn (gen_andsi3 (operands[0], operands[0], const1_rtx)); emit_insn (gen_rotlsi3_31 (operands[0], operands[0])); return; } } } else if (value == 0) { /* This can happen when not optimizing. We must output something here to prevent the compiler from aborting in final.c after the try_split call. */ emit_insn (gen_nop ()); return; } max = shift_insns[value]; for (i = 0; i < max; i++) gen_ashift (code, shift_amounts[value][i], operands[0]);} /* Same as above, but optimized for values where the topmost bits don't matter. */voidgen_shifty_hi_op (code, operands) int code; rtx *operands;{ int value = INTVAL (operands[2]); int max, i; void (*gen_fun) PARAMS ((int, int, rtx)); /* This operation is used by and_shl for SImode values with a few high bits known to be cleared. */ value &= 31; if (value == 0) { emit_insn (gen_nop ()); return; } gen_fun = GET_MODE (operands[0]) == HImode ? gen_ashift_hi : gen_ashift; if (code == ASHIFT) { max = ext_shift_insns[value]; for (i = 0; i < max; i++) gen_fun (code, ext_shift_amounts[value][i], operands[0]); } else /* When shifting right, emit the shifts in reverse order, so that solitary negative values come first. */ for (i = ext_shift_insns[value] - 1; i >= 0; i--) gen_fun (code, ext_shift_amounts[value][i], operands[0]);}/* Output RTL for an arithmetic right shift. *//* ??? Rewrite to use super-optimizer sequences. */intexpand_ashiftrt (operands) rtx *operands;{ rtx sym; rtx wrk; char func[18]; tree func_name; int value; if (TARGET_SH3) { if (GET_CODE (operands[2]) != CONST_INT) { rtx count = copy_to_mode_reg (SImode, operands[2]); emit_insn (gen_negsi2 (count, count)); emit_insn (gen_ashrsi3_d (operands[0], operands[1], count)); return 1; } else if (ashiftrt_insns[INTVAL (operands[2]) & 31] > 1 + SH_DYNAMIC_SHIFT_COST) { rtx count = force_reg (SImode, GEN_INT (- (INTVAL (operands[2]) & 31))); emit_insn (gen_ashrsi3_d (operands[0], operands[1], count)); return 1; } } if (GET_CODE (operands[2]) != CONST_INT) return 0; value = INTVAL (operands[2]) & 31; if (value == 31) { emit_insn (gen_ashrsi2_31 (operands[0], operands[1])); return 1; } else if (value >= 16 && value <= 19) { wrk = gen_reg_rtx (SImode); emit_insn (gen_ashrsi2_16 (wrk, operands[1])); value -= 16; while (value--) gen_ashift (ASHIFTRT, 1, wrk); emit_move_insn (operands[0], wrk); return 1; } /* Expand a short sequence inline, longer call a magic routine. */ else if (value <= 5) { wrk = gen_reg_rtx (SImode); emit_move_insn (wrk, operands[1]); while (value--) gen_ashift (ASHIFTRT, 1, wrk); emit_move_insn (operands[0], wrk); return 1; } wrk = gen_reg_rtx (Pmode); /* Load the value into an arg reg and call a helper. */ emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]); sprintf (func, "__ashiftrt_r4_%d", value); func_name = get_identifier (func); sym = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (func_name)); emit_move_insn (wrk, sym); emit_insn (gen_ashrsi3_n (GEN_INT (value), wrk)); emit_move_insn (operands[0], gen_rtx_REG (SImode, 4)); return 1;}intsh_dynamicalize_shift_p (count) rtx count;{ return shift_insns[INTVAL (count)] > 1 + SH_DYNAMIC_SHIFT_COST;}/* Try to find a good way to implement the combiner pattern [(set (match_operand:SI 0 "register_operand" "r") (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "const_int_operand" "n")) (match_operand:SI 3 "const_int_operand" "n"))) . LEFT_RTX is operand 2 in the above pattern, and MASK_RTX is operand 3. return 0 for simple right / left or left/right shift combination. return 1 for a combination of shifts with zero_extend. return 2 for a combination of shifts with an AND that needs r0. return 3 for a combination of shifts with an AND that needs an extra scratch register, when the three highmost bits of the AND mask are clear. return 4 for a combination of shifts with an AND that needs an extra scratch register, when any of the three highmost bits of the AND mask is set. If ATTRP is set, store an initial right shift width in ATTRP[0], and the instruction length in ATTRP[1] . These values are not valid when returning 0. When ATTRP is set and returning 1, ATTRP[2] gets set to the index into shift_amounts for the last shift value that is to be used before the sign extend. */intshl_and_kind (left_rtx, mask_rtx, attrp) rtx left_rtx, mask_rtx; int *attrp;{ unsigned HOST_WIDE_INT mask, lsb, mask2, lsb2; int left = INTVAL (left_rtx), right; int best = 0; int cost, best_cost = 10000; int best_right = 0, best_len = 0; int i; int can_ext; if (left < 0 || left > 31) return 0; if (GET_CODE (mask_rtx) == CONST_INT) mask = (unsigned HOST_WIDE_INT) INTVAL (mask_rtx) >> left; else mask = (unsigned HOST_WIDE_INT) GET_MODE_MASK (SImode) >> left; /* Can this be expressed as a right shift / left shift pair ? */ lsb = ((mask ^ (mask - 1)) >> 1) + 1; right = exact_log2 (lsb); mask2 = ~(mask + lsb - 1); lsb2 = ((mask2 ^ (mask2 - 1)) >> 1) + 1; /* mask has no zeroes but trailing zeroes <==> ! mask2 */ if (! mask2) best_cost = shift_insns[right] + shift_insns[right + left]; /* mask has no trailing zeroes <==> ! right */ else if (! right && mask2 == ~(lsb2 - 1)) { int late_right = exact_log2 (lsb2); best_cost = shift_insns[left + late_right] + shift_insns[late_right]; } /* Try to use zero extend */ if (mask2 == ~(lsb2 - 1)) { int width, first; for (width = 8; width <= 16; width += 8) { /* Can we zero-extend right away? */ if (lsb2 == (unsigned HOST_WIDE_INT)1 << width) { cost = 1 + ext_shift_insns[right] + ext_shift_insns[left + right]; if (cost < best_cost) { best = 1; best_cost = cost; best_right = right; best_len = cost; if (attrp) attrp[2] = -1; } continue; } /* ??? Could try to put zero extend into initial right shift, or even shift a bit left before the right shift. */ /* Determine value of first part of left shift, to get to the zero extend cut-off point. */ first = width - exact_log2 (lsb2) + right; if (first >= 0 && right + left - first >= 0) { cost = ext_shift_insns[right] + ext_shift_insns[first] + 1 + ext_shift_insns[right + left - first]; if (cost < best_cost) { best = 1; best_cost = cost; best_right = right; best_len = cost; if (attrp) attrp[2] = first; } } } } /* Try to use r0 AND pattern */ for (i = 0; i <= 2; i++) { if (i > right) break; if (! CONST_OK_FOR_L (mask >> i)) continue; cost = (i != 0) + 2 + ext_shift_insns[left + i]; if (cost < best_cost) { best = 2; best_cost = cost; best_right = i; best_len = cost - 1; } } /* Try to use a scratch register to hold the AND operand. */ can_ext = ((mask << left) & ((unsigned HOST_WIDE_INT)3 << 30)) == 0; for (i = 0; i <= 2; i++) { if (i > right) break; cost = (i != 0) + (CONST_OK_FOR_I (mask >> i) ? 2 : 3) + (can_ext ? ext_shift_insns : shift_insns)[left + i]; if (cost < best_cost) { best = 4 - can_ext; best_cost = cost; best_right = i; best_len = cost - 1 - ! CONST_OK_FOR_I (mask >> i); } } if (attrp) { attrp[0] = best_right; attrp[1] = best_len; } return best;}/* This is used in length attributes of the unnamed instructions corresponding to shl_and_kind return values of 1 and 2. */intshl_and_length (insn) rtx insn;{ rtx set_src, left_rtx, mask_rtx; int attributes[3]; set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); left_rtx = XEXP (XEXP (set_src, 0), 1); mask_rtx = XEXP (set_src, 1); shl_and_kind (left_rtx, mask_rtx, attributes); return attributes[1];}/* This is used in length attribute of the and_shl_scratch instruction. */intshl_and_scr_length (insn) rtx insn;{ rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); int len = shift_insns[INTVAL (XEXP (set_src, 1))]; rtx op = XEXP (set_src, 0); len += shift_insns[INTVAL (XEXP (op, 1))] + 1; op = XEXP (XEXP (op, 0), 0); return len + shift_insns[INTVAL (XEXP (op, 1))];}/* Generating rtl? */extern int rtx_equal_function_value_matters;/* Generate rtl for instructions for which shl_and_kind advised a particular method of generating them, i.e. returned zero. */intgen_shl_and (dest, left_rtx, mask_rtx, source) rtx dest, left_rtx, mask_rtx, source;{ int attributes[3]; unsigned HOST_WIDE_INT mask; int kind = shl_and_kind (left_rtx, mask_rtx, attributes); int right, total_shift; void (*shift_gen_fun) PARAMS ((int, rtx*)) = gen_shifty_hi_op; right = attributes[0]; total_shift = INTVAL (left_rtx) + right; mask = (unsigned HOST_WIDE_INT) INTVAL (mask_rtx) >> total_shift; switch (kind) { default: return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -