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] New target-hook: mode_rep_extended


This patch is the rework of my previous attempt to expose enough
information about !TRULY_NOOP_TRUNCATION targets so that the
middle-end can safely eliminate unnecessary TRUNCATE operations.

The version implements Richard Sandiford's suggestion to present this
not as a property of the TRUNCATE operation but as the property of the
mode requiring the TRUNCATE operation.  Or with MIPS64 as an example
we want to express this property of SImode:

  (subreg:DI foo:SI 0) == (sign_extend:DI foo:SI)

The patch adds a new target-hook TARGET_MODE_REP_EXTENDED(MODE,
MODE_REP) with the meaning that if the target represents MODE
internally as extended to MODE_REP this hook should return the type of
the extension.

I only made SIGN_EXTEND work for now because I don't know of any
target that has this property with ZERO_EXTEND.  So currently the hook
can only return UNKNOWN or SIGN_EXTEND.  LOAD_EXTEND_OP has a similar
interface and the two are related so I thought even though we might
never actually return ZERO_EXTEND here it still is the good idea to
keep the same format.

At this point the information provided by the hook is only used by
truncated_to_mode.  To decide whether a TRUNCATE can be replaced with
narrowing SUBREG the code checks if the reprentation required by the
destination mode is already satisfied by the value.  The table
num_sign_bit_copies_in_rep derived from the hook contains for each
pair of modes the number of sign-bit copies that must be present in
the wider mode to satisify the representation of the narrower mode.
E.g. for MIPS64:

    \NARROWER  QI   HI   SI   DI   TI
  WIDER		        
		        
   QI		        
   HI           0       
   SI           0    0      
   DI          32   32   32  
   TI          96   96   96    0   

Given this information we can also derive the definition for
TRULY_NOOP_TRUNCATION.  I am planning to default the value of
TRULY_NOOP_TRUNCATION based on this table.

Please note the comment before init_num_sign_bit_copies_in_rep because
I am not sure the assumption described there is correct.  On MIPS it
is certainly the case that QI and HImode values satisfy the
representation of SImode.  That way we can do arithmetic on them in
SImode.  However, I am not sure how to check for this property (optabs
maybe?) and whether I should.

Initially I had the hook return rtx_code but it turns out that
rtx_code is not always available at that point so I just applied the
same work-around as what rtx_costs had and used int.

I boostrapped and tested the patch on i686-pc-linux-gnu and tested it
on mipsisa64-elf.  The patch still removes the same number of
truncations as the previous version did.  The documentation change was
tested with make dvi.

Comments?  OK to apply?

Adam

	* target.h (struct gcc_target): Add mode_rep_extended.
	* rtlanal.c (num_sign_bit_copies_in_rep): New global.
	(init_num_sign_bit_copies_in_rep): Initialize it using
	mode_rep_extended.
	(truncate_to_mode): Use it.
	(init_rtlanal): Call init_num_sign_bit_copies_in_rep.
	* targhooks.h (default_mode_rep_extended): Declare it.
	* targhooks.c (default_mode_rep_extended): Define it.
	* target-def.h (TARGET_MODE_REP_EXTENDED): New macro.  Default to
	default_mode_rep_extended.
	(TARGET_INITIALIZER): Include it.
	* doc/tm.texi (Misc): Document it.
	* config/mips/mips.c (TARGET_TRUNCATED_TO_MODE): Override it.
	(mips_truncated_to_mode): New function.

Index: doc/tm.texi
===================================================================
--- doc/tm.texi	(revision 111958)
+++ doc/tm.texi	(working copy)
@@ -9074,6 +9074,31 @@ If this is the case, making @code{TRULY_
 such cases may improve things.
 @end defmac
 
+@deftypefn {Target Hook} int TARGET_MODE_REP_EXTENDED (enum machine_mode @var{mode}, enum machine_mode @var{rep_mode})
+The representation of an intergral mode can be such that the values are
+always extended to a wider integral mode.  Return @code{SIGN_EXTEND} if
+values of @var{mode} are represented in sign-extended form to
+@var{rep_mode}.  Return @code{UNKNOWN} otherwise.  (Currently, none of
+the targets use zero-extended representation this way so unlike
+@code{LOAD_EXTEND_OP}, @code{TARGET_MODE_REP_EXTENDED} is expected to
+return either @code{SIGN_EXTEND} or @code{UNKNOWN}.)
+
+Similarly to @code{LOAD_EXTEND_OP} you may return a non-@code{UNKNOWN}
+value even if the extension is not performed on certain hard registers
+as long as for the @code{REGNO_REG_CLASS} of these hard registers
+@code{CANNOT_CHANGE_MODE_CLASS} returns nonzero.
+
+Note that @code{TARGET_MODE_REP_EXTENDED} and @code{LOAD_EXTEND_OP}
+describe two related properties.  If you define
+@code{TARGET_MODE_REP_EXTENDED (mode, word_mode)} you probably also want
+to define @code{LOAD_EXTEND_OP (mode)} to return the same type of
+extension.
+
+In order to enforce the representation of @code{mode},
+@code{TRULY_NOOP_TRUNCATION} should return false when truncating to
+@code{mode}.
+@end deftypefn
+
 @defmac STORE_FLAG_VALUE
 A C expression describing the value returned by a comparison operator
 with an integral mode and stored by a store-flag instruction
Index: targhooks.c
===================================================================
--- targhooks.c	(revision 111958)
+++ targhooks.c	(working copy)
@@ -156,6 +156,15 @@ default_min_divisions_for_recip_mul (enu
   return have_insn_for (DIV, mode) ? 3 : 2;
 }
 
+/* The default implementation of TARGET_MODE_REP_EXTENDED.  */
+
+int
+default_mode_rep_extended (enum machine_mode mode ATTRIBUTE_UNUSED,
+			   enum machine_mode mode_rep ATTRIBUTE_UNUSED)
+{
+  return UNKNOWN;
+}
+
 /* Generic hook that takes a CUMULATIVE_ARGS pointer and returns true.  */
 
 bool
Index: targhooks.h
===================================================================
--- targhooks.h	(revision 111958)
+++ targhooks.h	(working copy)
@@ -34,6 +34,7 @@ extern enum machine_mode default_eh_retu
 extern unsigned HOST_WIDE_INT default_shift_truncation_mask
   (enum machine_mode);
 extern unsigned int default_min_divisions_for_recip_mul (enum machine_mode);
+int default_mode_rep_extended (enum machine_mode, enum machine_mode);
 
 extern tree default_stack_protect_guard (void);
 extern tree default_external_stack_protect_fail (void);
Index: target.h
===================================================================
--- target.h	(revision 111958)
+++ target.h	(working copy)
@@ -462,6 +462,14 @@ struct gcc_target
      the reciprocal.  */
   unsigned int (* min_divisions_for_recip_mul) (enum machine_mode mode);
 
+  /* If the representation of integral MODE is such that values are
+     always sign-extended to a wider mode MODE_REP then return
+     SIGN_EXTEND.  Return UNKNOWN otherwise.  */
+  /* Note that the return type ought to be RTX_CODE, but that's not
+     necessarily defined at this point.  */
+  int (* mode_rep_extended) (enum machine_mode mode,
+			     enum machine_mode mode_rep);
+
   /* True if MODE is valid for a pointer in __attribute__((mode("MODE"))).  */
   bool (* valid_pointer_mode) (enum machine_mode mode);
 
Index: rtlanal.c
===================================================================
--- rtlanal.c	(revision 111958)
+++ rtlanal.c	(working copy)
@@ -67,6 +67,21 @@ static int non_rtx_starting_operands[NUM
    and set by `-m...' switches.  Must be defined in rtlanal.c.  */
 
 int target_flags;
+
+/* Truncation narrows the mode from SOURCE mode to DESTINATION mode.
+   If TARGET_MODE_REP_EXTENDED (DESTINATION, DESTINATION_REP) is
+   SIGN_EXTEND then while narrowing we also have to enforce the
+   representation and sign-extend the value to mode DESTINATION_REP.
+
+   If the value is already sign-extended to DESTINATION_REP mode we
+   can just simply switch to DESTINATION mode on it.  For each pair of
+   integral modes SOURCE and DESTINATION, when truncating from SOURCE
+   to DESTINATION, the table NUM_SIGN_BIT_COPIES_IN_REP contains the
+   number of high-order bits in SOURCE that have to be copies of the
+   sign-bit so that we can do this mode-switch to DESTINATION.  */
+
+static unsigned int
+num_sign_bit_copies_in_rep[MAX_MODE_INT + 1][MAX_MODE_INT + 1];
 
 /* Return 1 if the value of X is unstable
    (would be different at a different point in the program).
@@ -4632,6 +4647,44 @@ get_condition (rtx jump, rtx *earliest, 
 				 allow_cc_mode, valid_at_insn_p);
 }
 
+/* Initialize the table NUM_SIGN_BIT_COPIES_IN_REP based on
+   TARGET_MODE_REP_EXTENDED.
+
+   Note that we assume that the property of
+   TARGET_MODE_REP_EXTENDED(B, C) is sticky to the integral modes
+   narrower than mode B.  I.e., if A is a mode narrower than B then in
+   order to be able to operate on it in mode B, mode A needs to
+   satisfy the requirements set by the representation of mode B.  */
+
+static void
+init_num_sign_bit_copies_in_rep (void)
+{
+  enum machine_mode mode, in_mode;
+
+  for (mode = MIN_MODE_INT; mode <= MAX_MODE_INT; mode++)
+    for (in_mode = MIN_MODE_INT; in_mode <= MAX_MODE_INT; in_mode++)
+      {
+	enum machine_mode i;
+
+	if (GET_MODE_SIZE (in_mode) <= GET_MODE_SIZE (mode))
+	  continue;
+
+	for (i = mode; i != in_mode; i = GET_MODE_WIDER_MODE (i))
+	  {
+	    enum machine_mode wider = GET_MODE_WIDER_MODE (i);
+
+	    if (targetm.mode_rep_extended (i, wider) == SIGN_EXTEND
+		/* We can only check sign-bit copies starting from the
+		   top-bit.  In order to be able to check the ones we
+		   have already seen we pretend that subsequent ones
+		   have to be sign-bit copies too.  */
+		|| num_sign_bit_copies_in_rep [mode][in_mode])
+	      num_sign_bit_copies_in_rep [mode][in_mode]
+		+= GET_MODE_BITSIZE (wider) - GET_MODE_BITSIZE (i);
+	  }
+      }
+}
+
 /* Suppose that truncation from the machine mode of X to MODE is not a
    no-op.  See if there is anything special about X so that we can
    assume it already contains a truncated value of MODE.  */
@@ -4639,9 +4692,20 @@ get_condition (rtx jump, rtx *earliest, 
 bool
 truncated_to_mode (enum machine_mode mode, rtx x)
 {
-  return REG_P (x) && rtl_hooks.reg_truncated_to_mode (mode, x);
-}
+  /* This register has already been used in MODE without explicit
+     truncation.  */
+  if (REG_P (x) && rtl_hooks.reg_truncated_to_mode (mode, x))
+    return true;
+
+  /* See if we already satisfy the requirements of MODE.  If yes we
+     can just switch to MODE.  */
+  if (num_sign_bit_copies_in_rep[mode][GET_MODE (x)]
+      && (num_sign_bit_copies (x, GET_MODE (x))
+	  >= num_sign_bit_copies_in_rep[mode][GET_MODE (x)] + 1))
+    return true;
 
+  return false;
+}
 
 /* Initialize non_rtx_starting_operands, which is used to speed up
    for_each_rtx.  */
@@ -4655,6 +4719,8 @@ init_rtlanal (void)
       const char *first = strpbrk (format, "eEV");
       non_rtx_starting_operands[i] = first ? first - format : -1;
     }
+
+  init_num_sign_bit_copies_in_rep ();
 }
 
 /* Check whether this is a constant pool constant.  */
Index: target-def.h
===================================================================
--- target-def.h	(revision 111958)
+++ target-def.h	(working copy)
@@ -358,6 +358,10 @@ Foundation, 51 Franklin Street, Fifth Fl
 #define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL default_min_divisions_for_recip_mul
 #endif
 
+#ifndef TARGET_MODE_REP_EXTENDED
+#define TARGET_MODE_REP_EXTENDED default_mode_rep_extended
+#endif
+
 #ifndef TARGET_VALID_POINTER_MODE
 #define TARGET_VALID_POINTER_MODE default_valid_pointer_mode
 #endif
@@ -620,6 +624,7 @@ Foundation, 51 Franklin Street, Fifth Fl
   TARGET_STRIP_NAME_ENCODING,			\
   TARGET_SHIFT_TRUNCATION_MASK,			\
   TARGET_MIN_DIVISIONS_FOR_RECIP_MUL,		\
+  TARGET_MODE_REP_EXTENDED,			\
   TARGET_VALID_POINTER_MODE,                    \
   TARGET_SCALAR_MODE_SUPPORTED_P,		\
   TARGET_VECTOR_MODE_SUPPORTED_P,               \
Index: config/mips/mips.c
===================================================================
--- config/mips/mips.c	(revision 111958)
+++ config/mips/mips.c	(working copy)
@@ -409,6 +409,7 @@ static rtx mips_expand_builtin_compare (
 static rtx mips_expand_builtin_bposge (enum mips_builtin_type, rtx);
 static void mips_encode_section_info (tree, rtx, int);
 static void mips_extra_live_on_entry (bitmap);
+static int mips_mode_rep_extended (enum machine_mode, enum machine_mode);
 
 /* Structure to be filled in by compute_frame_size with register
    save masks, and offsets for the current function.  */
@@ -1139,6 +1140,9 @@ static struct mips_rtx_cost_data const m
 #undef TARGET_ARG_PARTIAL_BYTES
 #define TARGET_ARG_PARTIAL_BYTES mips_arg_partial_bytes
 
+#undef TARGET_MODE_REP_EXTENDED
+#define TARGET_MODE_REP_EXTENDED mips_mode_rep_extended
+
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P mips_vector_mode_supported_p
 
@@ -10634,5 +10638,15 @@ mips_extra_live_on_entry (bitmap regs)
     bitmap_set_bit (regs, PIC_FUNCTION_ADDR_REGNUM);
 }
 
+/* SImode values are represented as sign-extended to DImode.  */
+
+int
+mips_mode_rep_extended (enum machine_mode mode, enum machine_mode mode_rep)
+{
+  if (TARGET_64BIT && mode == SImode && mode_rep == DImode)
+    return SIGN_EXTEND;
+
+  return UNKNOWN;
+}
 
 #include "gt-mips.h"


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