📄 sh.c
字号:
case 1: { int first = attributes[2]; rtx operands[3]; if (first < 0) { emit_insn ((mask << right) <= 0xff ? gen_zero_extendqisi2(dest, gen_lowpart (QImode, source)) : gen_zero_extendhisi2(dest, gen_lowpart (HImode, source))); source = dest; } if (source != dest) emit_insn (gen_movsi (dest, source)); operands[0] = dest; if (right) { operands[2] = GEN_INT (right); gen_shifty_hi_op (LSHIFTRT, operands); } if (first > 0) { operands[2] = GEN_INT (first); gen_shifty_hi_op (ASHIFT, operands); total_shift -= first; mask <<= first; } if (first >= 0) emit_insn (mask <= 0xff ? gen_zero_extendqisi2(dest, gen_lowpart (QImode, dest)) : gen_zero_extendhisi2(dest, gen_lowpart (HImode, dest))); if (total_shift > 0) { operands[2] = GEN_INT (total_shift); gen_shifty_hi_op (ASHIFT, operands); } break; } case 4: shift_gen_fun = gen_shifty_op; case 3: /* If the topmost bit that matters is set, set the topmost bits that don't matter. This way, we might be able to get a shorter signed constant. */ if (mask & ((HOST_WIDE_INT)1 << (31 - total_shift))) mask |= (HOST_WIDE_INT)~0 << (31 - total_shift); case 2: /* Don't expand fine-grained when combining, because that will make the pattern fail. */ if (rtx_equal_function_value_matters || reload_in_progress || reload_completed) { rtx operands[3]; /* Cases 3 and 4 should be handled by this split only while combining */ if (kind > 2) abort (); if (right) { emit_insn (gen_lshrsi3 (dest, source, GEN_INT (right))); source = dest; } emit_insn (gen_andsi3 (dest, source, GEN_INT (mask))); if (total_shift) { operands[0] = dest; operands[1] = dest; operands[2] = GEN_INT (total_shift); shift_gen_fun (ASHIFT, operands); } break; } else { int neg = 0; if (kind != 4 && total_shift < 16) { neg = -ext_shift_amounts[total_shift][1]; if (neg > 0) neg -= ext_shift_amounts[total_shift][2]; else neg = 0; } emit_insn (gen_and_shl_scratch (dest, source, GEN_INT (right), GEN_INT (mask), GEN_INT (total_shift + neg), GEN_INT (neg))); emit_insn (gen_movsi (dest, dest)); break; } } return 0;}/* Try to find a good way to implement the combiner pattern [(set (match_operand:SI 0 "register_operand" "=r") (sign_extract: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") (const_int 0))) (clobber (reg:SI T_REG))] LEFT_RTX is operand 2 in the above pattern, and SIZE_RTX is operand 3. return 0 for simple left / right shift combination. return 1 for left shift / 8 bit sign extend / left shift. return 2 for left shift / 16 bit sign extend / left shift. return 3 for left shift / 8 bit sign extend / shift / sign extend. return 4 for left shift / 16 bit sign extend / shift / sign extend. return 5 for left shift / 16 bit sign extend / right shift return 6 for < 8 bit sign extend / left shift. return 7 for < 8 bit sign extend / left shift / single right shift. If COSTP is nonzero, assign the calculated cost to *COSTP. */intshl_sext_kind (left_rtx, size_rtx, costp) rtx left_rtx, size_rtx; int *costp;{ int left, size, insize, ext; int cost, best_cost; int kind; left = INTVAL (left_rtx); size = INTVAL (size_rtx); insize = size - left; if (insize <= 0) abort (); /* Default to left / right shift. */ kind = 0; best_cost = shift_insns[32 - insize] + ashiftrt_insns[32 - size]; if (size <= 16) { /* 16 bit shift / sign extend / 16 bit shift */ cost = shift_insns[16 - insize] + 1 + ashiftrt_insns[16 - size]; /* If ashiftrt_insns[16 - size] is 8, this choice will be overridden below, by alternative 3 or something even better. */ if (cost < best_cost) { kind = 5; best_cost = cost; } } /* Try a plain sign extend between two shifts. */ for (ext = 16; ext >= insize; ext -= 8) { if (ext <= size) { cost = ext_shift_insns[ext - insize] + 1 + shift_insns[size - ext]; if (cost < best_cost) { kind = ext / (unsigned) 8; best_cost = cost; } } /* Check if we can do a sloppy shift with a final signed shift restoring the sign. */ if (EXT_SHIFT_SIGNED (size - ext)) cost = ext_shift_insns[ext - insize] + ext_shift_insns[size - ext] + 1; /* If not, maybe it's still cheaper to do the second shift sloppy, and do a final sign extend? */ else if (size <= 16) cost = ext_shift_insns[ext - insize] + 1 + ext_shift_insns[size > ext ? size - ext : ext - size] + 1; else continue; if (cost < best_cost) { kind = ext / (unsigned) 8 + 2; best_cost = cost; } } /* Check if we can sign extend in r0 */ if (insize < 8) { cost = 3 + shift_insns[left]; if (cost < best_cost) { kind = 6; best_cost = cost; } /* Try the same with a final signed shift. */ if (left < 31) { cost = 3 + ext_shift_insns[left + 1] + 1; if (cost < best_cost) { kind = 7; best_cost = cost; } } } if (TARGET_SH3) { /* Try to use a dynamic shift. */ cost = shift_insns[32 - insize] + 1 + SH_DYNAMIC_SHIFT_COST; if (cost < best_cost) { kind = 0; best_cost = cost; } } if (costp) *costp = cost; return kind;}/* Function to be used in the length attribute of the instructions implementing this pattern. */intshl_sext_length (insn) rtx insn;{ rtx set_src, left_rtx, size_rtx; int cost; set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); left_rtx = XEXP (XEXP (set_src, 0), 1); size_rtx = XEXP (set_src, 1); shl_sext_kind (left_rtx, size_rtx, &cost); return cost;}/* Generate rtl for this pattern */intgen_shl_sext (dest, left_rtx, size_rtx, source) rtx dest, left_rtx, size_rtx, source;{ int kind; int left, size, insize, cost; rtx operands[3]; kind = shl_sext_kind (left_rtx, size_rtx, &cost); left = INTVAL (left_rtx); size = INTVAL (size_rtx); insize = size - left; switch (kind) { case 1: case 2: case 3: case 4: { int ext = kind & 1 ? 8 : 16; int shift2 = size - ext; /* Don't expand fine-grained when combining, because that will make the pattern fail. */ if (! rtx_equal_function_value_matters && ! reload_in_progress && ! reload_completed) { emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx)); emit_insn (gen_movsi (dest, source)); break; } if (dest != source) emit_insn (gen_movsi (dest, source)); operands[0] = dest; if (ext - insize) { operands[2] = GEN_INT (ext - insize); gen_shifty_hi_op (ASHIFT, operands); } emit_insn (kind & 1 ? gen_extendqisi2(dest, gen_lowpart (QImode, dest)) : gen_extendhisi2(dest, gen_lowpart (HImode, dest))); if (kind <= 2) { if (shift2) { operands[2] = GEN_INT (shift2); gen_shifty_op (ASHIFT, operands); } } else { if (shift2 > 0) { if (EXT_SHIFT_SIGNED (shift2)) { operands[2] = GEN_INT (shift2 + 1); gen_shifty_op (ASHIFT, operands); operands[2] = GEN_INT (1); gen_shifty_op (ASHIFTRT, operands); break; } operands[2] = GEN_INT (shift2); gen_shifty_hi_op (ASHIFT, operands); } else if (shift2) { operands[2] = GEN_INT (-shift2); gen_shifty_hi_op (LSHIFTRT, operands); } emit_insn (size <= 8 ? gen_extendqisi2 (dest, gen_lowpart (QImode, dest)) : gen_extendhisi2 (dest, gen_lowpart (HImode, dest))); } break; } case 5: { int i = 16 - size; if (! rtx_equal_function_value_matters && ! reload_in_progress && ! reload_completed) emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx)); else { operands[0] = dest; operands[2] = GEN_INT (16 - insize); gen_shifty_hi_op (ASHIFT, operands); emit_insn (gen_extendhisi2 (dest, gen_lowpart (HImode, dest))); } /* Don't use gen_ashrsi3 because it generates new pseudos. */ while (--i >= 0) gen_ashift (ASHIFTRT, 1, dest); break; } case 6: case 7: /* Don't expand fine-grained when combining, because that will make the pattern fail. */ if (! rtx_equal_function_value_matters && ! reload_in_progress && ! reload_completed) { emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx)); emit_insn (gen_movsi (dest, source)); break; } emit_insn (gen_andsi3 (dest, source, GEN_INT ((1 << insize) - 1))); emit_insn (gen_xorsi3 (dest, dest, GEN_INT (1 << (insize - 1)))); emit_insn (gen_addsi3 (dest, dest, GEN_INT (-1 << (insize - 1)))); operands[0] = dest; operands[2] = kind == 7 ? GEN_INT (left + 1) : left_rtx; gen_shifty_op (ASHIFT, operands); if (kind == 7) emit_insn (gen_ashrsi3_k (dest, dest, GEN_INT (1))); break; default: return -1; } return 0;}/* Prefix a symbol_ref name with "datalabel". */rtxgen_datalabel_ref (sym) rtx sym;{ if (GET_CODE (sym) == LABEL_REF) return gen_rtx_CONST (GET_MODE (sym), gen_rtx_UNSPEC (GET_MODE (sym), gen_rtvec (1, sym), UNSPEC_DATALABEL)); if (GET_CODE (sym) != SYMBOL_REF) abort (); XSTR (sym, 0) = concat (SH_DATALABEL_ENCODING, XSTR (sym, 0), NULL); return sym;}/* The SH cannot load a large constant into a register, constants have to come from a pc relative load. The reference of a pc relative load instruction must be less than 1k infront of the instruction. This means that we often have to dump a constant inside a function, and generate code to branch around it. It is important to minimize this, since the branches will slow things down and make things bigger. Worst case code looks like: mov.l L1,rn bra L2 nop align L1: .long value L2: .. mov.l L3,rn bra L4 nop align L3: .long value L4: .. We fix this by performing a scan before scheduling, which notices which instructions need to have their operands fetched from the constant table and builds the table. The algorithm is: scan, find an instruction which needs a pcrel move. Look forward, find the last barrier which is within MAX_COUNT bytes of the requirement. If there isn't one, make one. Process all the instructions between the find and the barrier. In the above example, we can tell that L3 is within 1k of L1, so the first move can be shrunk from the 3 insn+constant sequence into just 1 insn, and the constant moved to L3 to make: mov.l L1,rn .. mov.l L3,rn bra L4 nop align L3:.long value L4:.long value Then the second move becomes the target for the shortening process. */typedef struct{ rtx value; /* Value in table. */ rtx label; /* Label of value. */ rtx wend; /* End of window. */ enum machine_mode mode; /* Mode of value. */ /* True if this constant is accessed as part of a post-increment sequence. Note that HImode constants are never accessed in this way. */ bool part_of_sequence_p;} pool_node;/* The maximum number of constants that can fit into one pool, since the pc relative range is 0...1020 bytes and constants are at least 4 bytes long. */#define MAX_POOL_SIZE (1020/4)static pool_node pool_vector[MAX_POOL_SIZE];static int pool_size;static rtx pool_window_label;static int pool_window_last;/* ??? If we need a constant in HImode which is the truncated value of a constant we need in SImode, we could combine the two entries thus saving two bytes. Is this common enough to be worth the effort of implementing it? *//* ??? This stuff should be done at the same time that we shorten branches. As
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -