📄 sh.c
字号:
if (CONST_OK_FOR_I08 (i)) return 2; /* Any other constants requires a 2 cycle pc-relative load plus an and. This case is probably unnecessary. */ return 3;}/* Return the cost of an addition or a subtraction. */static inline intaddsubcosts (rtx x){ /* Adding a register is a single cycle insn. */ if (GET_CODE (XEXP (x, 1)) == REG || GET_CODE (XEXP (x, 1)) == SUBREG) return 1; /* Likewise for small constants. */ if (GET_CODE (XEXP (x, 1)) == CONST_INT && CONST_OK_FOR_ADD (INTVAL (XEXP (x, 1)))) return 1; if (TARGET_SHMEDIA) switch (GET_CODE (XEXP (x, 1))) { case CONST: case LABEL_REF: case SYMBOL_REF: return TARGET_SHMEDIA64 ? 5 : 3; case CONST_INT: if (CONST_OK_FOR_I16 (INTVAL (XEXP (x, 1)))) return 2; else if (CONST_OK_FOR_I16 (INTVAL (XEXP (x, 1)) >> 16)) return 3; else if (CONST_OK_FOR_I16 ((INTVAL (XEXP (x, 1)) >> 16) >> 16)) return 4; /* Fall through. */ default: return 5; } /* Any other constant requires a 2 cycle pc-relative load plus an addition. */ return 3;}/* Return the cost of a multiply. */static inline intmultcosts (rtx x ATTRIBUTE_UNUSED){ if (TARGET_SHMEDIA) return 3; 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;}/* Compute a (partial) cost for rtx X. Return true if the complete cost has been computed, and false if subexpressions should be scanned. In either case, *TOTAL contains the cost result. */static boolsh_rtx_costs (rtx x, int code, int outer_code, int *total){ switch (code) { case CONST_INT: if (TARGET_SHMEDIA) { if (INTVAL (x) == 0) *total = 0; else if (outer_code == AND && and_operand ((x), DImode)) *total = 0; else if ((outer_code == IOR || outer_code == XOR || outer_code == PLUS) && CONST_OK_FOR_I10 (INTVAL (x))) *total = 0; else if (CONST_OK_FOR_I16 (INTVAL (x))) *total = COSTS_N_INSNS (outer_code != SET); else if (CONST_OK_FOR_I16 (INTVAL (x) >> 16)) *total = COSTS_N_INSNS (2); else if (CONST_OK_FOR_I16 ((INTVAL (x) >> 16) >> 16)) *total = COSTS_N_INSNS (3); else *total = COSTS_N_INSNS (4); return true; } if (CONST_OK_FOR_I08 (INTVAL (x))) *total = 0; else if ((outer_code == AND || outer_code == IOR || outer_code == XOR) && CONST_OK_FOR_K08 (INTVAL (x))) *total = 1; else *total = 8; return true; case CONST: case LABEL_REF: case SYMBOL_REF: if (TARGET_SHMEDIA64) *total = COSTS_N_INSNS (4); else if (TARGET_SHMEDIA32) *total = COSTS_N_INSNS (2); else *total = 5; return true; case CONST_DOUBLE: if (TARGET_SHMEDIA) *total = COSTS_N_INSNS (4); else *total = 10; return true; case PLUS: *total = COSTS_N_INSNS (addsubcosts (x)); return true; case AND: *total = COSTS_N_INSNS (andcosts (x)); return true; case MULT: *total = COSTS_N_INSNS (multcosts (x)); return true; case ASHIFT: case ASHIFTRT: case LSHIFTRT: *total = COSTS_N_INSNS (shiftcosts (x)); return true; case DIV: case UDIV: case MOD: case UMOD: *total = COSTS_N_INSNS (20); return true; case FLOAT: case FIX: *total = 100; return true; default: return false; }}/* Compute the cost of an address. For the SH, all valid addresses are the same cost. Use a slightly higher cost for reg + reg addressing, since it increases pressure on r0. */static intsh_address_cost (rtx X){ return (GET_CODE (X) == PLUS && ! CONSTANT_P (XEXP (X, 1)) && ! TARGET_SHMEDIA ? 1 : 0);}/* Code to expand a shift. */voidgen_ashift (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 (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 (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 (int code, rtx *operands){ int value = INTVAL (operands[2]); int max, i; void (*gen_fun) (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 (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 = function_symbol (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 (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 (rtx left_rtx, rtx mask_rtx, int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -