This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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.  */




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]