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]

Re: [PATCH][2 of 2] RTL expansion for zero sign extension elimination with VRP


Ping~

Thanks,
Kugan

+2013-09-25  Kugan Vivekanandarajah  <kuganv@linaro.org>
+
+	* dojump.c (do_compare_and_jump): Generate rtl without
+	zero/sign extension if redundant.
+	* cfgexpand.c (expand_gimple_stmt_1): Likewise.
+	* gimple.c (gimple_assign_is_zero_sign_ext_redundant) : New
+	function.
+	* gimple.h (gimple_assign_is_zero_sign_ext_redundant) : Declare.
+


On 26/09/13 18:04, Kugan Vivekanandarajah wrote:
> Hi,
> 
> This is the updated patch for expanding gimple stmts without zer/sign
> extensions when it is safe to do that. This is based on the
>  latest changes to propagating value range information to SSA_NAMEs
> and addresses review comments from Eric.
> 
> Bootstrapped and regtested on x86_64-unknown-linux-gnu and arm-none
> linux-gnueabi. Is this OK ?
> 
> Thanks,
> Kugan
> 

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 88e48c2..6a22f8b 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2311,6 +2311,20 @@ expand_gimple_stmt_1 (gimple stmt)
 
 	    if (temp == target)
 	      ;
+	    /* If the value in SUBREG of temp fits that SUBREG (does not
+	       overflow) and is assigned to target SUBREG of the same mode
+	       without sign convertion, we can skip the SUBREG
+	       and extension.  */
+	    else if (promoted
+		     && gimple_assign_is_zero_sign_ext_redundant (stmt)
+		     && (GET_CODE (temp) == SUBREG)
+		     && (GET_MODE_PRECISION (GET_MODE (SUBREG_REG (temp)))
+			 >= GET_MODE_PRECISION (GET_MODE (target)))
+		     && (GET_MODE (SUBREG_REG (target))
+			 == GET_MODE (SUBREG_REG (temp))))
+	      {
+		emit_move_insn (SUBREG_REG (target), SUBREG_REG (temp));
+	      }
 	    else if (promoted)
 	      {
 		int unsignedp = SUBREG_PROMOTED_UNSIGNED_P (target);
diff --git a/gcc/dojump.c b/gcc/dojump.c
index 3f04eac..9ea5995 100644
--- a/gcc/dojump.c
+++ b/gcc/dojump.c
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ggc.h"
 #include "basic-block.h"
 #include "tm_p.h"
+#include "gimple.h"
 
 static bool prefer_and_bit_test (enum machine_mode, int);
 static void do_jump_by_parts_greater (tree, tree, int, rtx, rtx, int);
@@ -1108,6 +1109,64 @@ do_compare_and_jump (tree treeop0, tree treeop1, enum rtx_code signed_code,
 
   type = TREE_TYPE (treeop0);
   mode = TYPE_MODE (type);
+
+  /* Is zero/sign extension redundant.  */
+  bool op0_ext_redundant = false;
+  bool op1_ext_redundant = false;
+
+  /* If promoted and the value in SUBREG of op0 fits (does not overflow),
+     it is a candidate for extension elimination.  */
+  if (GET_CODE (op0) == SUBREG && SUBREG_PROMOTED_VAR_P (op0))
+    op0_ext_redundant =
+      gimple_assign_is_zero_sign_ext_redundant (SSA_NAME_DEF_STMT (treeop0));
+
+  /* If promoted and the value in SUBREG of op1 fits (does not overflow),
+     it is a candidate for extension elimination.  */
+  if (GET_CODE (op1) == SUBREG && SUBREG_PROMOTED_VAR_P (op1))
+    op1_ext_redundant =
+      gimple_assign_is_zero_sign_ext_redundant (SSA_NAME_DEF_STMT (treeop1));
+
+  /* If zero/sign extension is redundant, generate RTL
+     for operands without zero/sign extension.  */
+  if ((op0_ext_redundant || TREE_CODE (treeop0) == INTEGER_CST)
+      && (op1_ext_redundant || TREE_CODE (treeop1) == INTEGER_CST))
+    {
+      if ((TREE_CODE (treeop1) == INTEGER_CST)
+	  && (!mode_signbit_p (GET_MODE (op1), op1)))
+	{
+	  /* First operand is constant and signbit is not set (not
+	     represented in RTL as a negative constant).  */
+	  rtx new_op0 = gen_reg_rtx (GET_MODE (SUBREG_REG (op0)));
+	  emit_move_insn (new_op0, SUBREG_REG (op0));
+	  op0 = new_op0;
+	}
+      else if ((TREE_CODE (treeop0) == INTEGER_CST)
+	       && (!mode_signbit_p (GET_MODE (op0), op0)))
+	{
+	  /* Other operand is constant and signbit is not set (not
+	     represented in RTL as a negative constant).  */
+	  rtx new_op1 = gen_reg_rtx (GET_MODE (SUBREG_REG (op1)));
+
+	  emit_move_insn (new_op1, SUBREG_REG (op1));
+	  op1 = new_op1;
+	}
+      else if ((TREE_CODE (treeop0) != INTEGER_CST)
+	       && (TREE_CODE (treeop1) != INTEGER_CST)
+	       && (GET_MODE (op0) == GET_MODE (op1))
+	       && (GET_MODE (SUBREG_REG (op0)) == GET_MODE (SUBREG_REG (op1))))
+	{
+	  /* Compare registers fits SUBREG and of the
+	     same mode.  */
+	  rtx new_op0 = gen_reg_rtx (GET_MODE (SUBREG_REG (op0)));
+	  rtx new_op1 = gen_reg_rtx (GET_MODE (SUBREG_REG (op1)));
+
+	  emit_move_insn (new_op0, SUBREG_REG (op0));
+	  emit_move_insn (new_op1, SUBREG_REG (op1));
+	  op0 = new_op0;
+	  op1 = new_op1;
+	}
+    }
+
   if (TREE_CODE (treeop0) == INTEGER_CST
       && (TREE_CODE (treeop1) != INTEGER_CST
           || (GET_MODE_BITSIZE (mode)
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 59fcf43..7bb93a6 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -200,6 +200,102 @@ gimple_call_reset_alias_info (gimple s)
     pt_solution_reset (gimple_call_clobber_set (s));
 }
 
+/* Check gimple assign stmt and see if zero/sign extension is
+   redundant.  i.e.  if an assignment gimple statement has RHS expression
+   value that can fit in LHS type, subreg and extension to fit can be
+   redundant.  Zero/sign extensions in this case can be removed.
+
+   If the assignment is
+   1) NOP_EXPR or CONVERT_EXPR:
+   Check value range of RHS to see if it fits LHS type.  If value fits type,
+   extension is redundant.
+
+   2) For all other types:
+   If the value range of LHS is less than the LHS TYPE_MAX and greater than
+   LHS TYPE_MIN, RHS expresion (from which LHS value range is derived)
+   will also have the same value range.  Therefore extension is redundant.  */
+
+bool
+gimple_assign_is_zero_sign_ext_redundant (gimple stmt)
+{
+  double_int type_min, type_max;
+  double_int min, max;
+  enum value_range_type range_type;
+  tree int_val = NULL_TREE;
+  enum tree_code stmt_code;
+  tree lhs, rhs1;
+
+  if (!is_gimple_assign (stmt))
+    return false;
+
+  stmt_code = gimple_assign_rhs_code (stmt);
+  lhs = gimple_assign_lhs (stmt);
+  rhs1 = gimple_assign_rhs1 (stmt);
+
+  /* We remove extension for non-pointer and integral stmts.  */
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+      || POINTER_TYPE_P (TREE_TYPE (lhs)))
+    return false;
+
+  type_max = tree_to_double_int (TYPE_MAX_VALUE (TREE_TYPE (lhs)));
+  type_min = tree_to_double_int (TYPE_MIN_VALUE (TREE_TYPE (lhs)));
+
+  if ((stmt_code == NOP_EXPR || stmt_code == CONVERT_EXPR))
+    {
+      if ((TREE_CODE (rhs1) != SSA_NAME)
+	  || (TYPE_UNSIGNED (TREE_TYPE (lhs))
+	      != TYPE_UNSIGNED (TREE_TYPE (rhs1))))
+	return false;
+
+      range_type = get_range_info (rhs1, &min, &max);
+
+      /* For NOP_EXPR and CONVERT_EXPR, if rhs value range fits lhs
+	 type, zero/sign extension is redundant.  */
+      if (range_type == VR_RANGE
+	  && max.cmp (type_max, TYPE_UNSIGNED (TREE_TYPE (lhs))) != 1
+	  && (type_min.cmp (min, TYPE_UNSIGNED (TREE_TYPE (lhs))) != 1))
+	return true;
+    }
+
+  /* For binary expressions, if one of the argument is constant and is
+     larger than signed maximum, it can be interpreted as negative
+     number and sign extended in RTL, so return false in this case.  */
+  if (TREE_CODE_CLASS (stmt_code) == tcc_binary)
+    {
+      tree rhs1 = gimple_assign_rhs1 (stmt);
+      tree rhs2 = gimple_assign_rhs2 (stmt);
+
+      if (TREE_CODE (rhs1) == INTEGER_CST)
+	int_val = rhs1;
+      else if (TREE_CODE (rhs2) == INTEGER_CST)
+	int_val = rhs2;
+
+      if (int_val != NULL_TREE)
+	{
+	  tree max = TYPE_MIN_VALUE (TREE_TYPE (lhs));
+
+	  /* If type is unsigned, get the max for signed equivalent.  */
+	  if (!INT_CST_LT (TYPE_MIN_VALUE (TREE_TYPE (lhs)), integer_zero_node))
+	    max = int_const_binop (RSHIFT_EXPR,
+				   max, build_int_cst (TREE_TYPE (max), 1));
+	  if (!INT_CST_LT (int_val, max))
+	    return false;
+	}
+    }
+
+  /* Get the value range.  */
+  range_type = get_range_info (lhs, &min, &max);
+
+  /* Value range fits type.  */
+  if (range_type == VR_RANGE
+      && (max.cmp (type_max, TYPE_UNSIGNED (TREE_TYPE (lhs))) == -1)
+      && ((type_min.cmp (min, TYPE_UNSIGNED (TREE_TYPE (lhs))) == -1)
+	  || min.is_zero ()))
+    return true;
+  return false;
+}
+
+
 /* Helper for gimple_build_call, gimple_build_call_valist,
    gimple_build_call_vec and gimple_build_call_from_tree.  Build the basic
    components of a GIMPLE_CALL statement to function FN with NARGS
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 5f12805..791f606 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -832,6 +832,7 @@ int gimple_call_flags (const_gimple);
 int gimple_call_return_flags (const_gimple);
 int gimple_call_arg_flags (const_gimple, unsigned);
 void gimple_call_reset_alias_info (gimple);
+bool gimple_assign_is_zero_sign_ext_redundant (gimple);
 bool gimple_assign_copy_p (gimple);
 bool gimple_assign_ssa_name_copy_p (gimple);
 bool gimple_assign_unary_nop_p (gimple);

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