RISC-V: Promode modes of constant loads for store insns.

Message ID 20190427004747.20369-1-jimw@sifive.com
State New
Headers show
Series
  • RISC-V: Promode modes of constant loads for store insns.
Related show

Commit Message

Jim Wilson April 27, 2019, 12:47 a.m.
This improves optimization of code storing constants to memory.  Given this
testcase:
    void sub1 (int *a, long long *b) { *a = 1; *b = 1; }
an unpatched rv64 compiler emits two li instructions, one for an SImode pseudo
and one for a DImode pseudo.  With the patch, we get a single DImode li insn.

This fixes the problem by promoting modes when we need to load a constant
that isn't valid as a src for a store instruction into a pseudo.  There is
some special handling for HImode stores which is preserved by passing the
original mode through.  This avoids a regression for testcases using HImode
stores.  There is a testcase added that shows the benefits of the optimization
and catches the cases that regressed with earlier versions of the patch.

This was tested with cross 32-bit/elf and 64-bit/linux builds and tests.  There
were no regressions.  The new testcase fails without the patch and works with
the patch.  This was also tested by looking at libc and libstdc++ code sizes.
This gives smaller code except in a few cases where moving an instruction out
of a loop required an extra prologue/epilogue store/load pair.

Committed.

Jim

	gcc/
	* config/riscv/riscv-protos.h (riscv_move_integer): Add machine_mode
	parameter.
	* config/riscv/riscv.c (riscv_move_integer): New parameter orig_mode.
	Pass orig_mode to riscv_build_integer.
	(riscv_split_integer): Pass mode to riscv_move_integer.
	(riscv_legitimize_const_move): Likewise.
	(riscv_legitimize_move): For MEM dest and CONST_INT src case, new local
	promoted_mode.  Replace force_reg call with code to load constant into
	promoted reg and then subreg it for the store.
	* config/riscv/riscv.md (low<mode>+1): Pass <GPR:MODE>mode to
	riscv_move_integer.

	gcc/testsuite/
	* gcc.target/riscv/load-immediate.c: New.
---
 gcc/config/riscv/riscv-protos.h               |  2 +-
 gcc/config/riscv/riscv.c                      | 42 +++++++++++++++----
 gcc/config/riscv/riscv.md                     |  3 +-
 .../gcc.target/riscv/load-immediate.c         | 32 ++++++++++++++
 4 files changed, 70 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/load-immediate.c

-- 
2.17.1

Patch

diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 8b510f87df8..5c1002bbc29 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -47,7 +47,7 @@  extern rtx riscv_emit_move (rtx, rtx);
 extern bool riscv_split_symbol (rtx, rtx, machine_mode, rtx *);
 extern bool riscv_split_symbol_type (enum riscv_symbol_type);
 extern rtx riscv_unspec_address (rtx, enum riscv_symbol_type);
-extern void riscv_move_integer (rtx, rtx, HOST_WIDE_INT);
+extern void riscv_move_integer (rtx, rtx, HOST_WIDE_INT, machine_mode);
 extern bool riscv_legitimize_move (machine_mode, rtx, rtx);
 extern rtx riscv_subword (rtx, bool);
 extern bool riscv_split_64bit_move_p (rtx, rtx);
diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
index e7440f39095..6fb6c6ad372 100644
--- a/gcc/config/riscv/riscv.c
+++ b/gcc/config/riscv/riscv.c
@@ -508,8 +508,8 @@  riscv_split_integer (HOST_WIDE_INT val, machine_mode mode)
   unsigned HOST_WIDE_INT hival = sext_hwi ((val - loval) >> 32, 32);
   rtx hi = gen_reg_rtx (mode), lo = gen_reg_rtx (mode);
 
-  riscv_move_integer (hi, hi, hival);
-  riscv_move_integer (lo, lo, loval);
+  riscv_move_integer (hi, hi, hival, mode);
+  riscv_move_integer (lo, lo, loval, mode);
 
   hi = gen_rtx_fmt_ee (ASHIFT, mode, hi, GEN_INT (32));
   hi = force_reg (mode, hi);
@@ -1334,10 +1334,12 @@  riscv_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
   return x;
 }
 
-/* Load VALUE into DEST.  TEMP is as for riscv_force_temporary.  */
+/* Load VALUE into DEST.  TEMP is as for riscv_force_temporary.  ORIG_MODE
+   is the original src mode before promotion.  */
 
 void
-riscv_move_integer (rtx temp, rtx dest, HOST_WIDE_INT value)
+riscv_move_integer (rtx temp, rtx dest, HOST_WIDE_INT value,
+		    machine_mode orig_mode)
 {
   struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS];
   machine_mode mode;
@@ -1345,7 +1347,9 @@  riscv_move_integer (rtx temp, rtx dest, HOST_WIDE_INT value)
   rtx x;
 
   mode = GET_MODE (dest);
-  num_ops = riscv_build_integer (codes, value, mode);
+  /* We use the original mode for the riscv_build_integer call, because HImode
+     values are given special treatment.  */
+  num_ops = riscv_build_integer (codes, value, orig_mode);
 
   if (can_create_pseudo_p () && num_ops > 2 /* not a simple constant */
       && num_ops >= riscv_split_integer_cost (value))
@@ -1381,7 +1385,7 @@  riscv_legitimize_const_move (machine_mode mode, rtx dest, rtx src)
   /* Split moves of big integers into smaller pieces.  */
   if (splittable_const_int_operand (src, mode))
     {
-      riscv_move_integer (dest, dest, INTVAL (src));
+      riscv_move_integer (dest, dest, INTVAL (src), mode);
       return;
     }
 
@@ -1428,7 +1432,31 @@  riscv_legitimize_move (machine_mode mode, rtx dest, rtx src)
 {
   if (!register_operand (dest, mode) && !reg_or_0_operand (src, mode))
     {
-      riscv_emit_move (dest, force_reg (mode, src));
+      rtx reg;
+
+      if (GET_CODE (src) == CONST_INT)
+	{
+	  /* Apply the equivalent of PROMOTE_MODE here for constants to
+	     improve cse.  */
+	  machine_mode promoted_mode = mode;
+	  if (GET_MODE_CLASS (mode) == MODE_INT
+	      && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+	    promoted_mode = word_mode;
+
+	  if (splittable_const_int_operand (src, mode))
+	    {
+	      reg = gen_reg_rtx (promoted_mode);
+	      riscv_move_integer (reg, reg, INTVAL (src), mode);
+	    }
+	  else
+	    reg = force_reg (promoted_mode, src);
+
+	  if (promoted_mode != mode)
+	    reg = gen_lowpart (mode, reg);
+	}
+      else
+	reg = force_reg (mode, src);
+      riscv_emit_move (dest, reg);
       return true;
     }
 
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index e3799a5bdd8..fc81daa43ef 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -1278,7 +1278,8 @@ 
   ""
   [(const_int 0)]
 {
-  riscv_move_integer (operands[2], operands[0], INTVAL (operands[1]));
+  riscv_move_integer (operands[2], operands[0], INTVAL (operands[1]),
+		      <GPR:MODE>mode);
   DONE;
 })
 
diff --git a/gcc/testsuite/gcc.target/riscv/load-immediate.c b/gcc/testsuite/gcc.target/riscv/load-immediate.c
new file mode 100644
index 00000000000..f8fe7473c31
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/load-immediate.c
@@ -0,0 +1,32 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O2" } */
+
+/* Check that we don't have unnecessary load immediate instructions.  */
+void
+sub1 (int *a, long long *b)
+{
+  *a = 1;
+  *b = 1;
+}
+
+void
+sub2 (short *a, short *b)
+{
+  *a = -32768;
+  *b = 32767;
+}
+
+void
+sub3 (int *a, long long *b)
+{
+  *a = 10000;
+  *b = 10000;
+}
+
+void
+sub4 (int *a, short *b)
+{
+  *a = 1;
+  *b = 1;
+}
+/* { dg-final { scan-assembler-times "\tli\t" 4 } } */