📄 unroll.c
字号:
if (code == IOR) increment = GEN_INT (INTVAL (increment) | INTVAL (second_part)); else if (code == PLUS) increment = GEN_INT (INTVAL (increment) + INTVAL (second_part)); else increment = GEN_INT (INTVAL (increment) << INTVAL (second_part)); } if (GET_CODE (increment) != CONST_INT) abort (); /* The insn loading the constant into a register is no longer needed, so delete it. */ delete_insn (get_last_insn ()); } if (increment_total) increment_total = GEN_INT (INTVAL (increment_total) + INTVAL (increment)); else increment_total = increment; /* Check that the source register is the same as the register we expected to see as the source. If not, something is seriously wrong. */ if (GET_CODE (XEXP (SET_SRC (pattern), 0)) != REG || REGNO (XEXP (SET_SRC (pattern), 0)) != regno) { /* Some machines (e.g. the romp), may emit two add instructions for certain constants, so lets try looking for another add immediately before this one if we have only seen one add insn so far. */ if (tries == 0) { tries++; src_insn = PREV_INSN (src_insn); pattern = PATTERN (src_insn); delete_insn (get_last_insn ()); goto retry; } abort (); } return increment_total;}/* Copy REG_NOTES, except for insn references, because not all insn_map entries are valid yet. We do need to copy registers now though, because the reg_map entries can change during copying. */static rtxinitial_reg_note_copy (notes, map) rtx notes; struct inline_remap *map;{ rtx copy; if (notes == 0) return 0; copy = rtx_alloc (GET_CODE (notes)); PUT_MODE (copy, GET_MODE (notes)); if (GET_CODE (notes) == EXPR_LIST) XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (notes, 0), map); else if (GET_CODE (notes) == INSN_LIST) /* Don't substitute for these yet. */ XEXP (copy, 0) = XEXP (notes, 0); else abort (); XEXP (copy, 1) = initial_reg_note_copy (XEXP (notes, 1), map); return copy;}/* Fixup insn references in copied REG_NOTES. */static voidfinal_reg_note_copy (notes, map) rtx notes; struct inline_remap *map;{ rtx note; for (note = notes; note; note = XEXP (note, 1)) if (GET_CODE (note) == INSN_LIST) XEXP (note, 0) = map->insn_map[INSN_UID (XEXP (note, 0))];}/* Copy each instruction in the loop, substituting from map as appropriate. This is very similar to a loop in expand_inline_function. */ static voidcopy_loop_body (copy_start, copy_end, map, exit_label, last_iteration, unroll_type, start_label, loop_end, insert_before, copy_notes_from) rtx copy_start, copy_end; struct inline_remap *map; rtx exit_label; int last_iteration; enum unroll_types unroll_type; rtx start_label, loop_end, insert_before, copy_notes_from;{ rtx insn, pattern; rtx tem, copy; int dest_reg_was_split, i; rtx cc0_insn = 0; rtx final_label = 0; rtx giv_inc, giv_dest_reg, giv_src_reg; /* If this isn't the last iteration, then map any references to the start_label to final_label. Final label will then be emitted immediately after the end of this loop body if it was ever used. If this is the last iteration, then map references to the start_label to itself. */ if (! last_iteration) { final_label = gen_label_rtx (); map->label_map[CODE_LABEL_NUMBER (start_label)] = final_label; } else map->label_map[CODE_LABEL_NUMBER (start_label)] = start_label; start_sequence (); insn = copy_start; do { insn = NEXT_INSN (insn); map->orig_asm_operands_vector = 0; switch (GET_CODE (insn)) { case INSN: pattern = PATTERN (insn); copy = 0; giv_inc = 0; /* Check to see if this is a giv that has been combined with some split address givs. (Combined in the sense that `combine_givs' in loop.c has put two givs in the same register.) In this case, we must search all givs based on the same biv to find the address givs. Then split the address givs. Do this before splitting the giv, since that may map the SET_DEST to a new register. */ if (GET_CODE (pattern) == SET && GET_CODE (SET_DEST (pattern)) == REG && addr_combined_regs[REGNO (SET_DEST (pattern))]) { struct iv_class *bl; struct induction *v, *tv; int regno = REGNO (SET_DEST (pattern)); v = addr_combined_regs[REGNO (SET_DEST (pattern))]; bl = reg_biv_class[REGNO (v->src_reg)]; /* Although the giv_inc amount is not needed here, we must call calculate_giv_inc here since it might try to delete the last insn emitted. If we wait until later to call it, we might accidentally delete insns generated immediately below by emit_unrolled_add. */ giv_inc = calculate_giv_inc (pattern, insn, regno); /* Now find all address giv's that were combined with this giv 'v'. */ for (tv = bl->giv; tv; tv = tv->next_iv) if (tv->giv_type == DEST_ADDR && tv->same == v) { int this_giv_inc; /* If this DEST_ADDR giv was not split, then ignore it. */ if (*tv->location != tv->dest_reg) continue; /* Scale this_giv_inc if the multiplicative factors of the two givs are different. */ this_giv_inc = INTVAL (giv_inc); if (tv->mult_val != v->mult_val) this_giv_inc = (this_giv_inc / INTVAL (v->mult_val) * INTVAL (tv->mult_val)); tv->dest_reg = plus_constant (tv->dest_reg, this_giv_inc); *tv->location = tv->dest_reg; if (last_iteration && unroll_type != UNROLL_COMPLETELY) { /* Must emit an insn to increment the split address giv. Add in the const_adjust field in case there was a constant eliminated from the address. */ rtx value, dest_reg; /* tv->dest_reg will be either a bare register, or else a register plus a constant. */ if (GET_CODE (tv->dest_reg) == REG) dest_reg = tv->dest_reg; else dest_reg = XEXP (tv->dest_reg, 0); /* Check for shared address givs, and avoid incrementing the shared pseudo reg more than once. */ if (! tv->same_insn) { /* tv->dest_reg may actually be a (PLUS (REG) (CONST)) here, so we must call plus_constant to add the const_adjust amount before calling emit_unrolled_add below. */ value = plus_constant (tv->dest_reg, tv->const_adjust); /* The constant could be too large for an add immediate, so can't directly emit an insn here. */ emit_unrolled_add (dest_reg, XEXP (value, 0), XEXP (value, 1)); } /* Reset the giv to be just the register again, in case it is used after the set we have just emitted. We must subtract the const_adjust factor added in above. */ tv->dest_reg = plus_constant (dest_reg, - tv->const_adjust); *tv->location = tv->dest_reg; } } } /* If this is a setting of a splittable variable, then determine how to split the variable, create a new set based on this split, and set up the reg_map so that later uses of the variable will use the new split variable. */ dest_reg_was_split = 0; if (GET_CODE (pattern) == SET && GET_CODE (SET_DEST (pattern)) == REG && splittable_regs[REGNO (SET_DEST (pattern))]) { int regno = REGNO (SET_DEST (pattern)); dest_reg_was_split = 1; /* Compute the increment value for the giv, if it wasn't already computed above. */ if (giv_inc == 0) giv_inc = calculate_giv_inc (pattern, insn, regno); giv_dest_reg = SET_DEST (pattern); giv_src_reg = SET_DEST (pattern); if (unroll_type == UNROLL_COMPLETELY) { /* Completely unrolling the loop. Set the induction variable to a known constant value. */ /* The value in splittable_regs may be an invariant value, so we must use plus_constant here. */ splittable_regs[regno] = plus_constant (splittable_regs[regno], INTVAL (giv_inc)); if (GET_CODE (splittable_regs[regno]) == PLUS) { giv_src_reg = XEXP (splittable_regs[regno], 0); giv_inc = XEXP (splittable_regs[regno], 1); } else { /* The splittable_regs value must be a REG or a CONST_INT, so put the entire value in the giv_src_reg variable. */ giv_src_reg = splittable_regs[regno]; giv_inc = const0_rtx; } } else { /* Partially unrolling loop. Create a new pseudo register for the iteration variable, and set it to be a constant plus the original register. Except on the last iteration, when the result has to go back into the original iteration var register. */ /* Handle bivs which must be mapped to a new register when split. This happens for bivs which need their final value set before loop entry. The new register for the biv was stored in the biv's first struct induction entry by find_splittable_regs. */ if (regno < max_reg_before_loop && reg_iv_type[regno] == BASIC_INDUCT) { giv_src_reg = reg_biv_class[regno]->biv->src_reg; giv_dest_reg = giv_src_reg; } #if 0 /* If non-reduced/final-value givs were split, then this would have to remap those givs also. See find_splittable_regs. */#endif splittable_regs[regno] = GEN_INT (INTVAL (giv_inc) + INTVAL (splittable_regs[regno])); giv_inc = splittable_regs[regno]; /* Now split the induction variable by changing the dest of this insn to a new register, and setting its reg_map entry to point to this new register. If this is the last iteration, and this is the last insn that will update the iv, then reuse the original dest, to ensure that the iv will have the proper value when the loop exits or repeats. Using splittable_regs_updates here like this is safe, because it can only be greater than one if all instructions modifying the iv are always executed in order. */ if (! last_iteration || (splittable_regs_updates[regno]-- != 1)) { tem = gen_reg_rtx (GET_MODE (giv_src_reg)); giv_dest_reg = tem; map->reg_map[regno] = tem; } else map->reg_map[regno] = giv_src_reg; } /* The constant being added could be too large for an add immediate, so can't directly emit an insn here. */ emit_unrolled_add (giv_dest_reg, giv_src_reg, giv_inc); copy = get_last_insn (); pattern = PATTERN (copy); } else { pattern = copy_rtx_and_substitute (pattern, map); copy = emit_insn (pattern); } REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map); #ifdef HAVE_cc0 /* If this insn is setting CC0, it may need to look at the insn that uses CC0 to see what type of insn it is. In that case, the call to recog via validate_change will fail. So don't substitute constants here. Instead, do it when we emit the following insn. For example, see the pyr.md file. That machine has signed and unsigned compares. The compare patterns must check the following branch insn to see which what kind of compare to emit. If the previous insn set CC0, substitute constants on it as well. */ if (sets_cc0_p (PATTERN (copy)) != 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -