This patch is a code density oriented and attempt to remove redundant sign/zero 
extension from assignment statement.
The approach taken is to use VRP data while expanding the assignment to RTL to 
determine whether a sign/zero extension is necessary.
Thought the motivation of the patch is code density but it also good for speed.

for example:
extern unsigned int func ();

  unsigned char
  foo (unsigned int arg)
  {
    if (arg == 2)
      return 0;

    return (func() == arg || arg == 7);
  }

the result of the comparison in the return will yield a False or True, which 
will be converted to integer and then casting to unsigned char.
this casting from integer to unsigned char is redundant because the value is 
either 0 or 1.

this patch is targeting the RISCV-32bit only.
This patch has been tested on a real embedded project and saved about 0.2% of 
code size.

P.S. I have an FSF license under Western Digital incorporation.
P.S. I've attached the patch as a file in case my email client corrupted the 
patch itself

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 9864e4344d2..c3739b2f331 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public 
License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
+#include <algorithm>
#include "config.h"
#include "system.h"
#include "coretypes.h"
@@ -73,6 +74,8 @@ along with GCC; see the file COPYING3.  If not see
#include "tree-ssa-address.h"
#include "output.h"
#include "builtins.h"
+#include "tree-vrp.h"
+
 /* Some systems use __main in a way incompatible with its use in gcc, in these
    cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
@@ -3640,6 +3643,107 @@ expand_clobber (tree lhs)
     }
}
+/* Print the ranges of the operand and save it to the dump file
+   used for debug purposes only.  */
+
+void
+print_range (tree operand, wide_int min, wide_int max)
+{
+  pretty_printer buffer;
+  pp_needs_newline (&buffer) = false;
+  buffer.buffer->stream = dump_file;
+  fprintf (dump_file, "Range for lhs: [");
+  pp_wide_int (&buffer, min, TYPE_SIGN (TREE_TYPE (operand)));
+  pp_printf (&buffer, ", ");
+  pp_wide_int (&buffer, max, TYPE_SIGN (TREE_TYPE (operand)));
+  pp_printf (&buffer, "]");
+  pp_flush (&buffer);
+  fprintf (dump_file, "\n");
+}
+
+
+
+/* Check that REG and SUBREG modes match between src and dest,
+   and that there is a cast to be removed.  */
+
+bool
+cast_to_remove_p (rtx src, rtx dest, machine_mode from
+                                                             , machine_mode to)
+{
+  if (GET_CODE (src) != SUBREG
+      || GET_CODE (dest) != SUBREG
+      || GET_CODE (SUBREG_REG (src)) != REG
+      || GET_CODE (SUBREG_REG (dest)) != REG
+      || GET_MODE (src) != GET_MODE (dest)
+      || GET_MODE (SUBREG_REG (src)) != GET_MODE (SUBREG_REG (dest))
+      || GET_MODE (src) != to
+      || GET_MODE (SUBREG_REG (src)) != from)
+    return false;
+  return true;
+}
+
+bool
+remove_cast_p (rtx temp, rtx target, gassign *assign_stmt)
+{
+  enum gimple_code code;
+  value_range_kind lhs_range, rhs_range;
+  unsigned int ops_num;
+  wide_int lhs_min, lhs_max, rhs_min, rhs_max;
+  if (gimple_assign_cast_p (assign_stmt))
+  {
+    code = gimple_code (assign_stmt);
+    ops_num = gimple_num_ops (assign_stmt);
+    if (code == GIMPLE_ASSIGN && ops_num < 3)
+    {
+      tree lhs = gimple_assign_lhs (assign_stmt);
+      if (POINTER_TYPE_P (TREE_TYPE (lhs)))
+       return false;
+      lhs_range = get_range_info (lhs, &lhs_min, &lhs_max);
+      if (dump_file && lhs_range == VR_RANGE)
+       print_range (lhs, lhs_min, lhs_max);
+
+      tree rhs = gimple_assign_rhs1 (assign_stmt);
+      if (POINTER_TYPE_P (TREE_TYPE (rhs)))
+       return false;
+      rhs_range = get_range_info (rhs, &rhs_min, &rhs_max);
+      if (rhs_range == VR_RANGE)
+      {
+       unsigned int rhs_precision
+             = std::max (wi::min_precision (rhs_max, TYPE_SIGN (TREE_TYPE 
(rhs))),
+                             wi::min_precision (rhs_min, TYPE_SIGN (TREE_TYPE 
(rhs))));
+       unsigned int lhs_precision = TYPE_PRECISION (TREE_TYPE (lhs));
+       if (lhs_precision > rhs_precision)
+       {
+
+             if (dump_file)
+             {
+                print_range (rhs, rhs_min, rhs_max);
+                if (lhs_precision > rhs_precision)
+                             fprintf (dump_file,
+                                 "EXPAND-CAST: This casting can be 
optimized\n");
+             }
+
+             return cast_to_remove_p (temp,
+                                             target,
+                                             TYPE_MODE (TREE_TYPE (rhs)),
+                                             TYPE_MODE (TREE_TYPE (lhs)));
+       }
+       else
+             if (dump_file)
+                fprintf (dump_file, "EXPAND-CAST: lhs_precision < 
rhs_precision\n");
+      }
+      else
+             if (dump_file)
+               fprintf (dump_file, "EXPAND-CAST: Range is not VR_RANGE\n");
+    }
+    else
+      if (dump_file)
+       fprintf (dump_file, "EXPAND-CAST: Got more than 2 ops \n");
+  }
+  return false;
+}
+
+
/* A subroutine of expand_gimple_stmt, expanding one gimple statement
    STMT that doesn't require special handling for outgoing edges.  That
    is no tailcalls and no GIMPLE_COND.  */
@@ -3801,6 +3905,11 @@ expand_gimple_stmt_1 (gimple *stmt)
                                   temp = convert_modes (GET_MODE (SUBREG_REG 
(target)),
                                                                                
 GET_MODE (target), temp, unsignedp);
                                 }
+                             if (targetm.remove_redundant_cast)
+                               if (remove_cast_p (temp,
+                                                                             
target,
+                                                                             
assign_stmt))
+                                 temp = SUBREG_REG (temp);
                                convert_move (SUBREG_REG (target), temp, 
unsignedp);
                     }
diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
index 94b5ac01762..504b1abf85e 100644
--- a/gcc/config/riscv/riscv.c
+++ b/gcc/config/riscv/riscv.c
@@ -5226,6 +5226,9 @@ riscv_hard_regno_rename_ok (unsigned from_regno 
ATTRIBUTE_UNUSED,
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG riscv_reorg
+#undef TARGET_REMOVE_REDUNDANT_CAST
+#define TARGET_REMOVE_REDUNDANT_CAST true
+
struct gcc_target targetm = TARGET_INITIALIZER;
 #include "gt-riscv.h"
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 19985adac3e..3a0d4813d96 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -12194,3 +12194,9 @@ This target hook can be used to generate a 
target-specific code
@deftypefn {Target Hook} void TARGET_RUN_TARGET_SELFTESTS (void)
If selftests are enabled, run any selftests for this target.
@end deftypefn
+
+@deftypevr {Target Hook} bool TARGET_REMOVE_REDUNDANT_CAST
+If this flag is true, @code{remove_cast_p} will be called
+and remove unneeded cast
+The default is false.
+@end deftypevr
\ No newline at end of file
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 1a16150bfc5..984e18e1697 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -8178,3 +8178,5 @@ maintainer is familiar with.
@hook TARGET_SPECULATION_SAFE_VALUE
 @hook TARGET_RUN_TARGET_SELFTESTS
+
+@hook TARGET_REMOVE_REDUNDANT_CAST
\ No newline at end of file
diff --git a/gcc/target.def b/gcc/target.def
index b5e82ff826e..014e5a22d4d 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6770,6 +6770,15 @@ following it should not be run.  Usually true only for 
virtual assembler\n\
targets.",
bool, false)
+/* True if remove_redundant_cast should be called to remove unneeded
+   casting.  */
+DEFHOOKPOD
+(remove_redundant_cast,
+ "If this flag is true, @code{remove_cast_p} will be called\n\
+and remove unneeded cast\n\
+The default is false.",
+ bool, false)
+
/* Leave the boolean fields at the end.  */
 /* Functions related to mode switching.  */
@@ -6835,4 +6844,3 @@ DEFHOOK
 /* Close the 'struct gcc_target' definition.  */
HOOK_VECTOR_END (C90_EMPTY_HACK)
-

-----------------------------------------------------------------------
Change log:

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 085ef66a207..ffe7e061985 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+2020-02-19  Nidal Faour <nidal.fa...@wdc.com>
+
+             * doc/tm.texi.in (TARGET_REMOVE_REDUNDANT_CAST): New hook.
+             * doc/tm.texi: Regenerate.
+             *cfgexpand.c (algorith.h): New include.
+             (tree-vrp.h): Likewise
+             (print_range): New function
+             (check_assign_can_be_free): Likewise
+             (adjust_assign_to_remove_cast): Likewise
+             (expand_gimple_stmt_1): Call adjust_assign_to_remove_cast
+             *config/riscv/riscv.c (TARGET_REMOVE_REDUNDANT_CAST): Define
+             *target.def (remove_redundant_cast): New target hook
+
2020-03-09  Jason Merrill  <ja...@redhat.com>
                * gdbinit.in (pgs): Fix typo in documentation.

diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f91af78a302..c5a701e08af 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2020-02-19  Nidal Faour  <nidal.fa...@wdc.com>
+       * gcc.target/riscv/masking-to-byte-1.c: New test
+       * gcc.target/riscv/masking-to-byte-2.c: New test
+
2020-03-09  Marek Polacek  <pola...@redhat.com>
                PR c++/92031 - bogus taking address of rvalue error.

Regards,
Nidal Faour

Attachment: remove-redundant-zero-extend.patch
Description: remove-redundant-zero-extend.patch

Reply via email to