diff gcc/lower-subreg.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
line wrap: on
line diff
--- a/gcc/lower-subreg.c	Thu Oct 25 07:37:49 2018 +0900
+++ b/gcc/lower-subreg.c	Thu Feb 13 11:34:05 2020 +0900
@@ -1,5 +1,5 @@
 /* Decompose multiword subregs.
-   Copyright (C) 2007-2018 Free Software Foundation, Inc.
+   Copyright (C) 2007-2020 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>
 		  Ian Lance Taylor <iant@google.com>
 
@@ -79,7 +79,7 @@
 static bitmap decomposable_context;
 
 /* Bit N in this bitmap is set if regno N is used in a context in
-   which it can not be decomposed.  */
+   which it cannot be decomposed.  */
 static bitmap non_decomposable_context;
 
 /* Bit N in this bitmap is set if regno N is used in a subreg
@@ -320,6 +320,24 @@
   return true;
 }
 
+/* If X is an operator that can be treated as a simple move that we
+   can split, then return the operand that is operated on.  */
+
+static rtx
+operand_for_swap_move_operator (rtx x)
+{
+  /* A word sized rotate of a register pair is equivalent to swapping
+     the registers in the register pair.  */
+  if (GET_CODE (x) == ROTATE
+      && GET_MODE (x) == twice_word_mode
+      && simple_move_operand (XEXP (x, 0))
+      && CONST_INT_P (XEXP (x, 1))
+      && INTVAL (XEXP (x, 1)) == BITS_PER_WORD)
+    return XEXP (x, 0);
+
+  return NULL_RTX;
+}
+
 /* If INSN is a single set between two objects that we want to split,
    return the single set.  SPEED_P says whether we are optimizing
    INSN for speed or size.
@@ -330,7 +348,7 @@
 static rtx
 simple_move (rtx_insn *insn, bool speed_p)
 {
-  rtx x;
+  rtx x, op;
   rtx set;
   machine_mode mode;
 
@@ -348,6 +366,9 @@
     return NULL_RTX;
 
   x = SET_SRC (set);
+  if ((op = operand_for_swap_move_operator (x)) != NULL_RTX)
+    x = op;
+
   if (x != recog_data.operand[0] && x != recog_data.operand[1])
     return NULL_RTX;
   /* For the src we can handle ASM_OPERANDS, and it is beneficial for
@@ -386,9 +407,13 @@
 {
   rtx dest = SET_DEST (set);
   rtx src = SET_SRC (set);
+  rtx op;
   unsigned int rd, rs;
   bitmap b;
 
+  if ((op = operand_for_swap_move_operator (src)) != NULL_RTX)
+    src = op;
+
   if (!REG_P (dest) || !REG_P (src))
     return false;
 
@@ -536,7 +561,7 @@
 	     the register.
 
 	     If this is not a simple copy from one location to another,
-	     then we can not decompose this register.  If this is a simple
+	     then we cannot decompose this register.  If this is a simple
 	     copy we want to decompose, and the mode is right,
 	     then we mark the register as decomposable.
 	     Otherwise we don't say anything about this register --
@@ -846,6 +871,21 @@
   return true;
 }
 
+/* OPND is a concatn operand this is used with a simple move operator.
+   Return a new rtx with the concatn's operands swapped.  */
+
+static rtx
+resolve_operand_for_swap_move_operator (rtx opnd)
+{
+  gcc_assert (GET_CODE (opnd) == CONCATN);
+  rtx concatn = copy_rtx (opnd);
+  rtx op0 = XVECEXP (concatn, 0, 0);
+  rtx op1 = XVECEXP (concatn, 0, 1);
+  XVECEXP (concatn, 0, 0) = op1;
+  XVECEXP (concatn, 0, 1) = op0;
+  return concatn;
+}
+
 /* Decompose the registers used in a simple move SET within INSN.  If
    we don't change anything, return INSN, otherwise return the start
    of the sequence of moves.  */
@@ -853,7 +893,7 @@
 static rtx_insn *
 resolve_simple_move (rtx set, rtx_insn *insn)
 {
-  rtx src, dest, real_dest;
+  rtx src, dest, real_dest, src_op;
   rtx_insn *insns;
   machine_mode orig_mode, dest_mode;
   unsigned int orig_size, words;
@@ -876,6 +916,23 @@
 
   real_dest = NULL_RTX;
 
+  if ((src_op = operand_for_swap_move_operator (src)) != NULL_RTX)
+    {
+      if (resolve_reg_p (dest))
+	{
+	  /* DEST is a CONCATN, so swap its operands and strip
+	     SRC's operator.  */
+	  dest = resolve_operand_for_swap_move_operator (dest);
+	  src = src_op;
+	}
+      else if (resolve_reg_p (src_op))
+	{
+	  /* SRC is an operation on a CONCATN, so strip the operator and
+	     swap the CONCATN's operands.  */
+	  src = resolve_operand_for_swap_move_operator (src_op);
+	}
+    }
+
   if (GET_CODE (src) == SUBREG
       && resolve_reg_p (SUBREG_REG (src))
       && (maybe_ne (SUBREG_BYTE (src), 0)
@@ -925,7 +982,7 @@
   /* It's possible for the code to use a subreg of a decomposed
      register while forming an address.  We need to handle that before
      passing the address to emit_move_insn.  We pass NULL_RTX as the
-     insn parameter to resolve_subreg_use because we can not validate
+     insn parameter to resolve_subreg_use because we cannot validate
      the insn yet.  */
   if (MEM_P (src) || MEM_P (dest))
     {
@@ -1744,7 +1801,8 @@
   {}
 
   /* opt_pass methods: */
-  virtual bool gate (function *) { return flag_split_wide_types != 0; }
+  virtual bool gate (function *) { return flag_split_wide_types
+					  && flag_split_wide_types_early; }
   virtual unsigned int execute (function *)
     {
       decompose_multiword_subregs (true);
@@ -1760,3 +1818,46 @@
 {
   return new pass_lower_subreg2 (ctxt);
 }
+
+/* Implement third lower subreg pass.  */
+
+namespace {
+
+const pass_data pass_data_lower_subreg3 =
+{
+  RTL_PASS, /* type */
+  "subreg3", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_LOWER_SUBREG, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_df_finish, /* todo_flags_finish */
+};
+
+class pass_lower_subreg3 : public rtl_opt_pass
+{
+public:
+  pass_lower_subreg3 (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_lower_subreg3, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return flag_split_wide_types
+					  && !flag_split_wide_types_early; }
+  virtual unsigned int execute (function *)
+    {
+      decompose_multiword_subregs (true);
+      return 0;
+    }
+
+}; // class pass_lower_subreg3
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_lower_subreg3 (gcc::context *ctxt)
+{
+  return new pass_lower_subreg3 (ctxt);
+}