/* Return true if INSN requires the stack frame to be set up. PROLOGUE_USED contains the hard registers used in the function prologue. SET_UP_BY_PROLOGUE is the set of registers we expect the prologue to set up for the function. */ bool requires_stack_frame_p (rtx_insn *insn, HARD_REG_SET prologue_used, HARD_REG_SET set_up_by_prologue) { df_ref def, use; HARD_REG_SET hardregs; unsigned regno; if (CALL_P (insn)) return !SIBLING_CALL_P (insn); /* We need a frame to get the unique CFA expected by the unwinder. */ if (cfun->can_throw_non_call_exceptions && can_throw_internal (insn)) return true; CLEAR_HARD_REG_SET (hardregs); FOR_EACH_INSN_DEF (def, insn) { rtx dreg = DF_REF_REG (def); if (!REG_P (dreg)) continue; add_to_hard_reg_set (&hardregs, GET_MODE (dreg), REGNO (dreg)); }
void fma_node::rename (fma_forest *forest) { int cur_parity, target_parity; /* This is alternate root of a chain and thus has no children. It will be renamed when processing the canonical root for that chain. */ if (!this->m_head) return; target_parity = forest->get_target_parity (); if (this->m_parent) target_parity = this->m_parent->get_parity (); cur_parity = this->get_parity (); /* Rename if parity differs. */ if (cur_parity != target_parity) { rtx_insn *insn = this->m_insn; HARD_REG_SET unavailable; enum machine_mode mode; int reg; if (dump_file) { unsigned cur_dest_reg = this->m_head->regno; fprintf (dump_file, "FMA or FMUL at insn %d but destination " "register (%s) has different parity from expected to " "maximize FPU pipeline utilization\n", INSN_UID (insn), reg_names[cur_dest_reg]); } /* Don't clobber traceback for noreturn functions. */ CLEAR_HARD_REG_SET (unavailable); if (frame_pointer_needed) { add_to_hard_reg_set (&unavailable, Pmode, FRAME_POINTER_REGNUM); add_to_hard_reg_set (&unavailable, Pmode, HARD_FRAME_POINTER_REGNUM); } /* Exclude registers with wrong parity. */ mode = GET_MODE (SET_DEST (PATTERN (insn))); for (reg = cur_parity; reg < FIRST_PSEUDO_REGISTER; reg += 2) add_to_hard_reg_set (&unavailable, mode, reg); if (!rename_single_chain (this->m_head, &unavailable)) { if (dump_file) fprintf (dump_file, "Destination register of insn %d could not be " "renamed. Dependent FMA insns will use this parity from " "there on.\n", INSN_UID (insn)); } else cur_parity = target_parity; } forest->get_globals ()->update_balance (cur_parity); }
DEBUG_FUNCTION void debug_value_data (struct value_data *vd) { HARD_REG_SET set; unsigned int i, j; CLEAR_HARD_REG_SET (set); for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) if (vd->e[i].oldest_regno == i) { if (vd->e[i].mode == VOIDmode) { if (vd->e[i].next_regno != INVALID_REGNUM) fprintf (stderr, "[%u] Bad next_regno for empty chain (%u)\n", i, vd->e[i].next_regno); continue; } SET_HARD_REG_BIT (set, i); fprintf (stderr, "[%u %s] ", i, GET_MODE_NAME (vd->e[i].mode)); for (j = vd->e[i].next_regno; j != INVALID_REGNUM; j = vd->e[j].next_regno) { if (TEST_HARD_REG_BIT (set, j)) { fprintf (stderr, "[%u] Loop in regno chain\n", j); return; } if (vd->e[j].oldest_regno != i) { fprintf (stderr, "[%u] Bad oldest_regno (%u)\n", j, vd->e[j].oldest_regno); return; } SET_HARD_REG_BIT (set, j); fprintf (stderr, "[%u %s] ", j, GET_MODE_NAME (vd->e[j].mode)); } fputc ('\n', stderr); } for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) if (! TEST_HARD_REG_BIT (set, i) && (vd->e[i].mode != VOIDmode || vd->e[i].oldest_regno != i || vd->e[i].next_regno != INVALID_REGNUM)) fprintf (stderr, "[%u] Non-empty reg in chain (%s %u %i)\n", i, GET_MODE_NAME (vd->e[i].mode), vd->e[i].oldest_regno, vd->e[i].next_regno); }
static void validate_value_data (struct value_data *vd) { HARD_REG_SET set; unsigned int i, j; CLEAR_HARD_REG_SET (set); for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) if (vd->e[i].oldest_regno == i) { if (vd->e[i].mode == VOIDmode) { if (vd->e[i].next_regno != INVALID_REGNUM) internal_error ("validate_value_data: [%u] Bad next_regno for empty chain (%u)", i, vd->e[i].next_regno); continue; } SET_HARD_REG_BIT (set, i); for (j = vd->e[i].next_regno; j != INVALID_REGNUM; j = vd->e[j].next_regno) { if (TEST_HARD_REG_BIT (set, j)) internal_error ("validate_value_data: Loop in regno chain (%u)", j); if (vd->e[j].oldest_regno != i) internal_error ("validate_value_data: [%u] Bad oldest_regno (%u)", j, vd->e[j].oldest_regno); SET_HARD_REG_BIT (set, j); } } for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) if (! TEST_HARD_REG_BIT (set, i) && (vd->e[i].mode != VOIDmode || vd->e[i].oldest_regno != i || vd->e[i].next_regno != INVALID_REGNUM)) internal_error ("validate_value_data: [%u] Non-empty reg in chain (%s %u %i)", i, GET_MODE_NAME (vd->e[i].mode), vd->e[i].oldest_regno, vd->e[i].next_regno); }
/* Update all offsets and possibility for elimination on eliminable registers. Spill pseudos assigned to registers which are uneliminable, update LRA_NO_ALLOC_REGS and ELIMINABLE_REG_SET. Add insns to INSNS_WITH_CHANGED_OFFSETS containing eliminable hard registers whose offsets should be changed. Return true if any elimination offset changed. */ static bool update_reg_eliminate (bitmap insns_with_changed_offsets) { bool prev, result; struct lra_elim_table *ep, *ep1; HARD_REG_SET temp_hard_reg_set; /* Clear self elimination offsets. */ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) self_elim_offsets[ep->from] = 0; for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) { /* If it is a currently used elimination: update the previous offset. */ if (elimination_map[ep->from] == ep) ep->previous_offset = ep->offset; prev = ep->prev_can_eliminate; setup_can_eliminate (ep, targetm.can_eliminate (ep->from, ep->to)); if (ep->can_eliminate && ! prev) { /* It is possible that not eliminable register becomes eliminable because we took other reasons into account to set up eliminable regs in the initial set up. Just ignore new eliminable registers. */ setup_can_eliminate (ep, false); continue; } if (ep->can_eliminate != prev && elimination_map[ep->from] == ep) { /* We cannot use this elimination anymore -- find another one. */ if (lra_dump_file != NULL) fprintf (lra_dump_file, " Elimination %d to %d is not possible anymore\n", ep->from, ep->to); /* If after processing RTL we decides that SP can be used as a result of elimination, it can not be changed. */ gcc_assert ((ep->to_rtx != stack_pointer_rtx) || (ep->from < FIRST_PSEUDO_REGISTER && fixed_regs [ep->from])); /* Mark that is not eliminable anymore. */ elimination_map[ep->from] = NULL; for (ep1 = ep + 1; ep1 < ®_eliminate[NUM_ELIMINABLE_REGS]; ep1++) if (ep1->can_eliminate && ep1->from == ep->from) break; if (ep1 < ®_eliminate[NUM_ELIMINABLE_REGS]) { if (lra_dump_file != NULL) fprintf (lra_dump_file, " Using elimination %d to %d now\n", ep1->from, ep1->to); lra_assert (ep1->previous_offset == 0); ep1->previous_offset = ep->offset; } else { /* There is no elimination anymore just use the hard register `from' itself. Setup self elimination offset to restore the original offset values. */ if (lra_dump_file != NULL) fprintf (lra_dump_file, " %d is not eliminable at all\n", ep->from); self_elim_offsets[ep->from] = -ep->offset; if (ep->offset != 0) bitmap_ior_into (insns_with_changed_offsets, &lra_reg_info[ep->from].insn_bitmap); } } INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, ep->offset); } setup_elimination_map (); result = false; CLEAR_HARD_REG_SET (temp_hard_reg_set); for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) if (elimination_map[ep->from] == NULL) SET_HARD_REG_BIT (temp_hard_reg_set, ep->from); else if (elimination_map[ep->from] == ep) { /* Prevent the hard register into which we eliminate from the usage for pseudos. */ if (ep->from != ep->to) SET_HARD_REG_BIT (temp_hard_reg_set, ep->to); if (ep->previous_offset != ep->offset) { bitmap_ior_into (insns_with_changed_offsets, &lra_reg_info[ep->from].insn_bitmap); /* Update offset when the eliminate offset have been changed. */ lra_update_reg_val_offset (lra_reg_info[ep->from].val, ep->offset - ep->previous_offset); result = true; } } IOR_HARD_REG_SET (lra_no_alloc_regs, temp_hard_reg_set); AND_COMPL_HARD_REG_SET (eliminable_regset, temp_hard_reg_set); spill_pseudos (temp_hard_reg_set); return result; }
static int reload_cse_simplify_operands (rtx insn, rtx testreg) { int i, j; /* For each operand, all registers that are equivalent to it. */ HARD_REG_SET equiv_regs[MAX_RECOG_OPERANDS]; const char *constraints[MAX_RECOG_OPERANDS]; /* Vector recording how bad an alternative is. */ int *alternative_reject; /* Vector recording how many registers can be introduced by choosing this alternative. */ int *alternative_nregs; /* Array of vectors recording, for each operand and each alternative, which hard register to substitute, or -1 if the operand should be left as it is. */ int *op_alt_regno[MAX_RECOG_OPERANDS]; /* Array of alternatives, sorted in order of decreasing desirability. */ int *alternative_order; extract_insn (insn); if (recog_data.n_alternatives == 0 || recog_data.n_operands == 0) return 0; /* Figure out which alternative currently matches. */ if (! constrain_operands (1)) fatal_insn_not_found (insn); alternative_reject = XALLOCAVEC (int, recog_data.n_alternatives); alternative_nregs = XALLOCAVEC (int, recog_data.n_alternatives); alternative_order = XALLOCAVEC (int, recog_data.n_alternatives); memset (alternative_reject, 0, recog_data.n_alternatives * sizeof (int)); memset (alternative_nregs, 0, recog_data.n_alternatives * sizeof (int)); /* For each operand, find out which regs are equivalent. */ for (i = 0; i < recog_data.n_operands; i++) { cselib_val *v; struct elt_loc_list *l; rtx op; enum machine_mode mode; CLEAR_HARD_REG_SET (equiv_regs[i]); /* cselib blows up on CODE_LABELs. Trying to fix that doesn't seem right, so avoid the problem here. Likewise if we have a constant and the insn pattern doesn't tell us the mode we need. */ if (LABEL_P (recog_data.operand[i]) || (CONSTANT_P (recog_data.operand[i]) && recog_data.operand_mode[i] == VOIDmode)) continue; op = recog_data.operand[i]; mode = GET_MODE (op); #ifdef LOAD_EXTEND_OP if (MEM_P (op) && GET_MODE_BITSIZE (mode) < BITS_PER_WORD && LOAD_EXTEND_OP (mode) != UNKNOWN) { rtx set = single_set (insn); /* We might have multiple sets, some of which do implicit extension. Punt on this for now. */ if (! set) continue; /* If the destination is also a MEM or a STRICT_LOW_PART, no extension applies. Also, if there is an explicit extension, we don't have to worry about an implicit one. */ else if (MEM_P (SET_DEST (set)) || GET_CODE (SET_DEST (set)) == STRICT_LOW_PART || GET_CODE (SET_SRC (set)) == ZERO_EXTEND || GET_CODE (SET_SRC (set)) == SIGN_EXTEND) ; /* Continue ordinary processing. */ #ifdef CANNOT_CHANGE_MODE_CLASS /* If the register cannot change mode to word_mode, it follows that it cannot have been used in word_mode. */ else if (REG_P (SET_DEST (set)) && CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)), word_mode, REGNO_REG_CLASS (REGNO (SET_DEST (set))))) ; /* Continue ordinary processing. */ #endif /* If this is a straight load, make the extension explicit. */ else if (REG_P (SET_DEST (set)) && recog_data.n_operands == 2 && SET_SRC (set) == op && SET_DEST (set) == recog_data.operand[1-i]) { validate_change (insn, recog_data.operand_loc[i], gen_rtx_fmt_e (LOAD_EXTEND_OP (mode), word_mode, op), 1); validate_change (insn, recog_data.operand_loc[1-i], gen_rtx_REG (word_mode, REGNO (SET_DEST (set))), 1); if (! apply_change_group ()) return 0; return reload_cse_simplify_operands (insn, testreg); } else /* ??? There might be arithmetic operations with memory that are safe to optimize, but is it worth the trouble? */ continue; } #endif /* LOAD_EXTEND_OP */ v = cselib_lookup (op, recog_data.operand_mode[i], 0); if (! v) continue; for (l = v->locs; l; l = l->next) if (REG_P (l->loc)) SET_HARD_REG_BIT (equiv_regs[i], REGNO (l->loc)); } for (i = 0; i < recog_data.n_operands; i++) { enum machine_mode mode; int regno; const char *p; op_alt_regno[i] = XALLOCAVEC (int, recog_data.n_alternatives); for (j = 0; j < recog_data.n_alternatives; j++) op_alt_regno[i][j] = -1; p = constraints[i] = recog_data.constraints[i]; mode = recog_data.operand_mode[i]; /* Add the reject values for each alternative given by the constraints for this operand. */ j = 0; while (*p != '\0') { char c = *p++; if (c == ',') j++; else if (c == '?') alternative_reject[j] += 3; else if (c == '!') alternative_reject[j] += 300; } /* We won't change operands which are already registers. We also don't want to modify output operands. */ regno = true_regnum (recog_data.operand[i]); if (regno >= 0 || constraints[i][0] == '=' || constraints[i][0] == '+') continue; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { int rclass = (int) NO_REGS; if (! TEST_HARD_REG_BIT (equiv_regs[i], regno)) continue; SET_REGNO (testreg, regno); PUT_MODE (testreg, mode); /* We found a register equal to this operand. Now look for all alternatives that can accept this register and have not been assigned a register they can use yet. */ j = 0; p = constraints[i]; for (;;) { char c = *p; switch (c) { case '=': case '+': case '?': case '#': case '&': case '!': case '*': case '%': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '<': case '>': case 'V': case 'o': case 'E': case 'F': case 'G': case 'H': case 's': case 'i': case 'n': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'p': case 'X': case TARGET_MEM_CONSTRAINT: /* These don't say anything we care about. */ break; case 'g': case 'r': rclass = reg_class_subunion[(int) rclass][(int) GENERAL_REGS]; break; default: rclass = (reg_class_subunion [(int) rclass] [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]); break; case ',': case '\0': /* See if REGNO fits this alternative, and set it up as the replacement register if we don't have one for this alternative yet and the operand being replaced is not a cheap CONST_INT. */ if (op_alt_regno[i][j] == -1 && reg_fits_class_p (testreg, rclass, 0, mode) && (GET_CODE (recog_data.operand[i]) != CONST_INT || (rtx_cost (recog_data.operand[i], SET, optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn))) > rtx_cost (testreg, SET, optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn)))))) { alternative_nregs[j]++; op_alt_regno[i][j] = regno; } j++; rclass = (int) NO_REGS; break; } p += CONSTRAINT_LEN (c, p); if (c == '\0') break; } } } /* Record all alternatives which are better or equal to the currently matching one in the alternative_order array. */ for (i = j = 0; i < recog_data.n_alternatives; i++) if (alternative_reject[i] <= alternative_reject[which_alternative]) alternative_order[j++] = i; recog_data.n_alternatives = j; /* Sort it. Given a small number of alternatives, a dumb algorithm won't hurt too much. */ for (i = 0; i < recog_data.n_alternatives - 1; i++) { int best = i; int best_reject = alternative_reject[alternative_order[i]]; int best_nregs = alternative_nregs[alternative_order[i]]; int tmp; for (j = i + 1; j < recog_data.n_alternatives; j++) { int this_reject = alternative_reject[alternative_order[j]]; int this_nregs = alternative_nregs[alternative_order[j]]; if (this_reject < best_reject || (this_reject == best_reject && this_nregs > best_nregs)) { best = j; best_reject = this_reject; best_nregs = this_nregs; } } tmp = alternative_order[best]; alternative_order[best] = alternative_order[i]; alternative_order[i] = tmp; } /* Substitute the operands as determined by op_alt_regno for the best alternative. */ j = alternative_order[0]; for (i = 0; i < recog_data.n_operands; i++) { enum machine_mode mode = recog_data.operand_mode[i]; if (op_alt_regno[i][j] == -1) continue; validate_change (insn, recog_data.operand_loc[i], gen_rtx_REG (mode, op_alt_regno[i][j]), 1); } for (i = recog_data.n_dups - 1; i >= 0; i--) { int op = recog_data.dup_num[i]; enum machine_mode mode = recog_data.operand_mode[op]; if (op_alt_regno[op][j] == -1) continue; validate_change (insn, recog_data.dup_loc[i], gen_rtx_REG (mode, op_alt_regno[op][j]), 1); } return apply_change_group (); }