Index: gcc/rtl-factoring.c =================================================================== --- gcc/rtl-factoring.c (revision 133102) +++ gcc/rtl-factoring.c (working copy) @@ -37,6 +37,8 @@ #include "output.h" #include "df.h" #include "addresses.h" +#include "insn-attr.h" +#include "recog.h" /* Sequence abstraction: @@ -202,6 +204,9 @@ /* The register used to hold the return address during the pseudo-call. */ rtx link_reg; + + /* The register for indirect jump. */ + rtx ijmp_reg; /* The sequences matching this pattern. */ matching_seq matching_seqs; @@ -271,6 +276,12 @@ /* Cost of returning. */ static int seq_return_cost; +/* Register class for indirect jump. */ +static enum reg_class ijmp_class; + +/* Use constant pool to store generated symbol references. */ +static int use_const_pool = 0; + /* Returns the first insn preceding INSN for which INSN_P is true and belongs to the same basic block. Returns NULL_RTX if no such insn can be found. */ @@ -308,9 +319,59 @@ return hash; } -/* Compute the cost of INSN rtx for abstraction. */ +/* Returns default length of INSN or its PATTERN if INSN isn't recognized. */ +static inline int +get_default_length (rtx insn) +{ + rtx body = PATTERN (insn); + if (recog_memoized (insn) >= 0) + return insn_default_length (insn); + else if (recog_memoized (body) >= 0) + return insn_default_length (body); + else + return 0; +} + +/* Compute the length of INSN. */ + static int +compute_rtx_length (rtx insn) +{ + rtx body; + int i; + int length = 0; + + switch (GET_CODE (insn)) + { + case CALL_INSN: + length = get_default_length (insn); + break; + + case JUMP_INSN: + length = get_default_length (insn); + break; + + case INSN: + body = PATTERN (insn); + if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER) + return 0; + else if (GET_CODE (body) == SEQUENCE) + for (i = 0; i < XVECLEN (body, 0); i++) + length += compute_rtx_length (XVECEXP (body, 0, i)); + else + length = get_default_length (insn); + break; + + default: + break; + } + return length; +} + +/* Compute and cache the cost of INSN rtx. */ + +static int compute_rtx_cost (rtx insn) { struct hash_bucket_def tmp_bucket; @@ -340,7 +401,7 @@ /* If we can't parse the INSN cost will be the instruction length. */ if (cost == -1) { - cost = get_attr_length (insn); + cost = compute_rtx_length (insn); /* Cache the length. */ if (elem) @@ -349,7 +410,7 @@ /* If we can't get an accurate estimate for a complex instruction, assume that it has the same cost as a single fast instruction. */ - return cost != 0 ? cost : COSTS_N_INSNS (1); + return cost > 0 ? cost : COSTS_N_INSNS (1); } /* Determines the number of common insns in the sequences ending in INSN1 and @@ -405,6 +466,7 @@ pseq->abstracted_length = 0; pseq->cost = 0; pseq->link_reg = NULL_RTX; + pseq->ijmp_reg = NULL_RTX; pseq->matching_seqs = NULL; pseq->next_pattern_seq = pattern_seqs; pattern_seqs = pseq; @@ -594,6 +656,7 @@ /* Initialize data. */ SET_HARD_REG_SET (linkregs); pseq->link_reg = NULL_RTX; + pseq->ijmp_reg = NULL_RTX; pseq->abstracted_length = 0; pseq->gain = -(seq_call_cost - seq_jump_cost + seq_return_cost); @@ -697,7 +760,7 @@ #else || (!ok_for_base_p_1 (i, Pmode, MEM, SCRATCH)) || (!reg_class_subset_p (REGNO_REG_CLASS (i), - base_reg_class (VOIDmode, MEM, SCRATCH))) + base_reg_class (VOIDmode, MEM, SCRATCH))) #endif || (hascall && call_used_regs[i]) || (!call_used_regs[i] && !df_regs_ever_live_p (i))) @@ -714,7 +777,28 @@ /* Abstraction is not possible if no link register is available, so set gain to 0. */ if (!pseq->link_reg) - pseq->gain = 0; + { + pseq->gain = 0; + return; + } + + if (reg_class_subset_p (REGNO_REG_CLASS (i), ijmp_class)) + return; + + /* Find a register for indirect jump. */ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (reg_class_subset_p (REGNO_REG_CLASS (i), ijmp_class) + && (!hascall || !call_used_regs[i]) + && (call_used_regs[i] || df_regs_ever_live_p (i))) + { + pseq->ijmp_reg = gen_rtx_REG (Pmode, i); + break; + } + if (!pseq->ijmp_reg) + { + pseq->gain = 0; + return; + } } /* Deallocates memory occupied by PSEQ and its matching seqs. */ @@ -938,7 +1022,7 @@ /* Builds a symbol_ref for LABEL. */ static rtx -gen_symbol_ref_rtx_for_label (const_rtx label) +gen_symbol_ref_rtx_for_label (rtx label) { char name[20]; rtx sym; @@ -946,6 +1030,10 @@ ASM_GENERATE_INTERNAL_LABEL (name, "L", CODE_LABEL_NUMBER (label)); sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_LOCAL; + if (use_const_pool) { + LABEL_PRESERVE_P (label) = 1; + return force_const_mem (Pmode, sym); + } return sym; } @@ -1004,7 +1092,7 @@ { rtx insn; basic_block bb; - rtx retlabel, retjmp, saveinsn; + rtx retlabel, saveinsn; int i; seq_block sb; @@ -1020,8 +1108,19 @@ /* Emit an indirect jump via the link register after the sequence acting as the return insn. Also emit a barrier and update the basic block. */ if (!find_reg_note (BB_END (bb), REG_NORETURN, NULL)) - retjmp = emit_jump_insn_after (gen_indirect_jump (pattern_seqs->link_reg), - BB_END (bb)); + { + if (!reg_class_subset_p (REGNO_REG_CLASS (REGNO (pattern_seqs->link_reg)), + ijmp_class)) + { + emit_insn_after (gen_move_insn (pattern_seqs->ijmp_reg, + pattern_seqs->link_reg), BB_END (bb)); + emit_jump_insn_after (gen_indirect_jump (pattern_seqs->ijmp_reg), + BB_END (bb)); + } + else + emit_jump_insn_after (gen_indirect_jump (pattern_seqs->link_reg), + BB_END (bb)); + } emit_barrier_after (BB_END (bb)); /* Replace all outgoing edges with a new one to the block of RETLABEL. */ @@ -1335,32 +1434,91 @@ static void compute_init_costs (void) { - rtx rtx_jump, rtx_store, rtx_return, reg, label; + rtx rtx_jump, rtx_store, rtx_return, reg, jmp_reg, label, tmp; basic_block bb; + int i, regno, jmpno; FOR_EACH_BB (bb) if (BB_HEAD (bb)) break; label = block_label (bb); - reg = gen_rtx_REG (Pmode, 0); + regno = 0; + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (regno_ok_for_base_p (i, Pmode, MEM, SCRATCH)) + { + regno = i; + break; + } + reg = gen_rtx_REG (Pmode, regno); + /* Pattern for indirect jump. */ rtx_jump = gen_indirect_jump (reg); - /* Pattern for storing address. */ - rtx_store = gen_rtx_SET (VOIDmode, reg, gen_symbol_ref_rtx_for_label (label)); + /* The cost of jump. */ + if (GET_CODE (rtx_jump) == JUMP_INSN) + tmp = rtx_jump; + else + tmp = make_jump_insn_raw (rtx_jump); + seq_jump_cost = compute_rtx_cost (tmp); - /* Pattern for return insn. */ - rtx_return = gen_jump (label); + /* Determine the register class for indirect jump. */ + extract_insn (tmp); + preprocess_constraints (); + ijmp_class = NO_REGS; + if (recog_data.n_operands == 1) + { + char c; + const char *p = recog_data.constraints[0]; + for (;(c = *p) != '\0';) + { + if (c == 'r' || c == 'g') + ijmp_class = GENERAL_REGS; + else + ijmp_class = REG_CLASS_FROM_CONSTRAINT (c, p); + + if (ijmp_class != NO_REGS) + break; + p += CONSTRAINT_LEN (c, p); + } + } - /* The cost of jump. */ - seq_jump_cost = compute_rtx_cost (make_jump_insn_raw (rtx_jump)); + jmpno = 0; + jmp_reg = NULL_RTX; + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (reg_class_subset_p (REGNO_REG_CLASS (i), ijmp_class)) + { + jmp_reg = gen_rtx_REG (Pmode, i); + jmpno = i; + break; + } + if (REGNO_REG_CLASS (regno) != REGNO_REG_CLASS (jmpno)) + seq_jump_cost += compute_rtx_cost (gen_move_insn (jmp_reg, reg)); + + /* Pattern for storing address. */ + rtx_store = gen_move_insn (reg, gen_symbol_ref_rtx_for_label (label)); + for (tmp = rtx_store; tmp; tmp = NEXT_INSN(tmp)) + if (recog_memoized(tmp) < 0 && GET_CODE (PATTERN (tmp)) != USE) + { + use_const_pool = 1; + break; + } + /* Try to use constant pool for symbol reference. */ + if (use_const_pool) + { + rtx_store = gen_move_insn (reg, gen_symbol_ref_rtx_for_label (label)); + for (tmp = rtx_store; tmp; tmp = NEXT_INSN(tmp)) + gcc_assert (recog_memoized(tmp) >= 0); + } + /* The cost of calling sequence. */ - seq_call_cost = seq_jump_cost + compute_rtx_cost (make_insn_raw (rtx_store)); + seq_call_cost = seq_jump_cost + compute_rtx_cost (rtx_store) + + COSTS_N_INSNS (use_const_pool); /* The cost of return. */ + rtx_return = gen_jump (label); seq_return_cost = compute_rtx_cost (make_jump_insn_raw (rtx_return)); /* Simple heuristic for minimal sequence cost. */