This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR33642, unrecognizable insn for -frtl-abstract-sequences
- From: Gábor Lóki <loki at inf dot u-szeged dot hu>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 13 Mar 2008 19:13:17 +0100
- Subject: [PATCH] Fix PR33642, unrecognizable insn for -frtl-abstract-sequences
Hi,
This patch fixes the PR33642 for rtl-factoring.c.
It contains the following modifications:
- Redesign the cost computation (based on 'get_attr_length'),
because the previous one fails on many targets.
- The generation of indirect jump sequence has been also modified.
An intermediate register move have been inserted before indirect jump
if the target requires it.
- Use constant pool if the target doesn't allow to store a symbol
reference directly to a register.
- Detect the need of intermediate register and constant pool during
initialization.
Bootstrapped on i686-linux, x86_64-linux.
Regtested on i686-linux, x86_64-linux, arm-eabi, mips-elf, powerpc-elf, sh-elf.
It has a known deficiency: fails into an 'unrecognizable insn' error on arm-eabi
with '-O0 -fPIC -frtl-abstract-sequences' flags.
Currently I don't know why, but I will look into it.
Ok for trunk?
--Gabor
2008-03-13 Gabor Loki <loki@gcc.gnu.org>
PR gcc/33642
* rtl-factoring.c (get_default_length, compute_rtx_length): New.
Computes the length of INSNs.
(compute_rtx_cost): Use COMPUTE_RTX_LENGTH instead of GET_ATTR_LENGTH.
(match_seqs): Initialize IJMP_REG field.
(recompute_gain_for_pattern_seq): Find a register for IJMP_REG.
(gen_symbol_ref_rtx_for_label): Force constant to memory if necessary.
(split_pattern_seq): Use IJMP_REG for indirect jump.
(compute_init_costs): Detect the need of intermediate register and
constant pool.
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. */