From decc676eb52a061b15df7eed9fead794458e9e09 Mon Sep 17 00:00:00 2001
From: Oleg Endo <olegendo@gcc.gnu.org>
Date: Wed, 13 Mar 2013 18:09:10 +0000
Subject: [PATCH] re PR target/49880 (SuperH: ICE when -m4 is used with
 -mdiv=call-div1)

	PR target/49880
	* config/sh/sh.opt (FPU_SINGLE_ONLY): New mask.
	(musermode): Convert to Var(TARGET_USERMODE).
	* config/sh/sh.h (SELECT_SH2A_SINGLE_ONLY, SELECT_SH4_SINGLE_ONLY,
	MASK_ARCH): Add MASK_FPU_SINGLE_ONLY.
	* config/sh/sh.c (sh_option_override): Use
	TARGET_FPU_DOUBLE || TARGET_FPU_SINGLE_ONLY for call-fp case.
	* config/sh/sh.md (udivsi3_i1, divsi3_i1): Remove ! TARGET_SH4
	condition.
	(udivsi3_i4, divsi3_i4): Use TARGET_FPU_DOUBLE condition instead of
	TARGET_SH4.
	(udivsi3_i4_single, divsi3_i4_single): Use
	TARGET_FPU_SINGLE_ONLY || TARGET_FPU_DOUBLE instead of TARGET_HARD_SH4.

	PR target/49880
	* config/sh/lib1funcs.S (sdivsi3_i4, udivsi3_i4): Enable for SH2A.
	(sdivsi3, udivsi3): Remove SH4 check and always compile these functions.

	PR target/49880
	* gcc.target/sh/pr49880-1.c: New.
	* gcc.target/sh/pr49880-2.c: New.
	* gcc.target/sh/pr49880-3.c: New.
	* gcc.target/sh/pr49880-4.c: New.
	* gcc.target/sh/pr49880-5.c: New.

From-SVN: r196636
---
 gcc/ChangeLog                           | 16 ++++++++++++++++
 gcc/config/sh/sh.c                      |  3 +--
 gcc/config/sh/sh.h                      |  9 ++++++---
 gcc/config/sh/sh.md                     | 14 ++++++++------
 gcc/config/sh/sh.opt                    |  6 +++++-
 gcc/testsuite/ChangeLog                 |  9 +++++++++
 gcc/testsuite/gcc.target/sh/pr49880-1.c | 22 ++++++++++++++++++++++
 gcc/testsuite/gcc.target/sh/pr49880-2.c | 22 ++++++++++++++++++++++
 gcc/testsuite/gcc.target/sh/pr49880-3.c | 22 ++++++++++++++++++++++
 gcc/testsuite/gcc.target/sh/pr49880-4.c | 19 +++++++++++++++++++
 gcc/testsuite/gcc.target/sh/pr49880-5.c | 19 +++++++++++++++++++
 libgcc/ChangeLog                        |  6 ++++++
 libgcc/config/sh/lib1funcs.S            | 16 ++++++----------
 13 files changed, 161 insertions(+), 22 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/sh/pr49880-1.c
 create mode 100644 gcc/testsuite/gcc.target/sh/pr49880-2.c
 create mode 100644 gcc/testsuite/gcc.target/sh/pr49880-3.c
 create mode 100644 gcc/testsuite/gcc.target/sh/pr49880-4.c
 create mode 100644 gcc/testsuite/gcc.target/sh/pr49880-5.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 78cccc822524..e2cd655971ac 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,19 @@
+2013-03-13  Oleg Endo  <olegendo@gcc.gnu.org>
+
+	PR target/49880
+	* config/sh/sh.opt (FPU_SINGLE_ONLY): New mask.
+	(musermode): Convert to Var(TARGET_USERMODE).
+	* config/sh/sh.h (SELECT_SH2A_SINGLE_ONLY, SELECT_SH4_SINGLE_ONLY,
+	MASK_ARCH): Add MASK_FPU_SINGLE_ONLY.
+	* config/sh/sh.c (sh_option_override): Use
+	TARGET_FPU_DOUBLE || TARGET_FPU_SINGLE_ONLY for call-fp case.
+	* config/sh/sh.md (udivsi3_i1, divsi3_i1): Remove ! TARGET_SH4
+	condition.
+	(udivsi3_i4, divsi3_i4): Use TARGET_FPU_DOUBLE condition instead of
+	TARGET_SH4.
+	(udivsi3_i4_single, divsi3_i4_single): Use
+	TARGET_FPU_SINGLE_ONLY || TARGET_FPU_DOUBLE instead of TARGET_HARD_SH4.
+
 2013-03-13  Dave Korn  <dave.korn.cygwin@....>
 
 	* config/i386/cygwin.h (SHARED_LIBGCC_SPEC): Make shared libgcc the
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index dcbd93286ed8..44e1e4ce30ef 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -816,8 +816,7 @@ sh_option_override (void)
       if (! strcmp (sh_div_str, "call-div1"))
 	sh_div_strategy = SH_DIV_CALL_DIV1;
       else if (! strcmp (sh_div_str, "call-fp")
-	       && (TARGET_FPU_DOUBLE
-		   || (TARGET_HARD_SH4 && TARGET_SH2E)
+	       && (TARGET_FPU_DOUBLE || TARGET_FPU_SINGLE_ONLY
 		   || (TARGET_SHCOMPACT && TARGET_FPU_ANY)))
 	sh_div_strategy = SH_DIV_CALL_FP;
       else if (! strcmp (sh_div_str, "call-table") && TARGET_DYNSHIFT)
diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
index ecd6c17e553c..3744f980fe75 100644
--- a/gcc/config/sh/sh.h
+++ b/gcc/config/sh/sh.h
@@ -138,14 +138,16 @@ extern int code_for_indirect_jump_scratch;
 				  | MASK_SH2 | MASK_SH1)
 #define SELECT_SH2A_NOFPU	 (MASK_HARD_SH2A | MASK_SH2 | MASK_SH1)
 #define SELECT_SH2A_SINGLE_ONLY  (MASK_SH_E | MASK_HARD_SH2A | MASK_SH2 \
-				  | MASK_SH1 | MASK_FPU_SINGLE)
+				  | MASK_SH1 | MASK_FPU_SINGLE \
+				  | MASK_FPU_SINGLE_ONLY)
 #define SELECT_SH2A_SINGLE	 (MASK_SH_E | MASK_HARD_SH2A \
 				  | MASK_FPU_SINGLE | MASK_HARD_SH2A_DOUBLE \
 				  | MASK_SH2 | MASK_SH1)
 #define SELECT_SH3		 (MASK_SH3 | SELECT_SH2)
 #define SELECT_SH3E		 (MASK_SH_E | MASK_FPU_SINGLE | SELECT_SH3)
 #define SELECT_SH4_NOFPU	 (MASK_HARD_SH4 | SELECT_SH3)
-#define SELECT_SH4_SINGLE_ONLY	 (MASK_HARD_SH4 | SELECT_SH3E)
+#define SELECT_SH4_SINGLE_ONLY	 (MASK_HARD_SH4 | SELECT_SH3E \
+				  | MASK_FPU_SINGLE_ONLY)
 #define SELECT_SH4		 (MASK_SH4 | MASK_SH_E | MASK_HARD_SH4 \
 				  | SELECT_SH3)
 #define SELECT_SH4_SINGLE	 (MASK_FPU_SINGLE | SELECT_SH4)
@@ -212,7 +214,8 @@ extern int code_for_indirect_jump_scratch;
 /* Reset all target-selection flags.  */
 #define MASK_ARCH (MASK_SH1 | MASK_SH2 | MASK_SH3 | MASK_SH_E | MASK_SH4 \
 		   | MASK_HARD_SH2A | MASK_HARD_SH2A_DOUBLE | MASK_SH4A \
-		   | MASK_HARD_SH4 | MASK_FPU_SINGLE | MASK_SH5)
+		   | MASK_HARD_SH4 | MASK_FPU_SINGLE | MASK_SH5 \
+		   | MASK_FPU_SINGLE_ONLY)
 
 /* This defaults us to big-endian.  */
 #ifndef TARGET_ENDIAN_DEFAULT
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 75b102c3fa74..42ef5e142d80 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -2154,7 +2154,7 @@
    (clobber (reg:SI PR_REG))
    (clobber (reg:SI R4_REG))
    (use (match_operand:SI 1 "arith_reg_operand" "r"))]
-  "TARGET_SH1 && (! TARGET_SH4 || TARGET_DIVIDE_CALL_DIV1)"
+  "TARGET_SH1 && TARGET_DIVIDE_CALL_DIV1"
   "jsr	@%1%#"
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
@@ -2217,7 +2217,7 @@
    (clobber (reg:SI R5_REG))
    (use (reg:PSI FPSCR_REG))
    (use (match_operand:SI 1 "arith_reg_operand" "r"))]
-  "TARGET_SH4 && ! TARGET_FPU_SINGLE"
+  "TARGET_FPU_DOUBLE && ! TARGET_FPU_SINGLE"
   "jsr	@%1%#"
   [(set_attr "type" "sfunc")
    (set_attr "fp_mode" "double")
@@ -2236,7 +2236,8 @@
    (clobber (reg:SI R4_REG))
    (clobber (reg:SI R5_REG))
    (use (match_operand:SI 1 "arith_reg_operand" "r"))]
-  "(TARGET_HARD_SH4 || TARGET_SHCOMPACT) && TARGET_FPU_SINGLE"
+  "(TARGET_FPU_SINGLE_ONLY || TARGET_FPU_DOUBLE || TARGET_SHCOMPACT)
+   && TARGET_FPU_SINGLE"
   "jsr	@%1%#"
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
@@ -2358,7 +2359,7 @@
    (clobber (reg:SI R2_REG))
    (clobber (reg:SI R3_REG))
    (use (match_operand:SI 1 "arith_reg_operand" "r"))]
-  "TARGET_SH1 && (! TARGET_SH4 || TARGET_DIVIDE_CALL_DIV1)"
+  "TARGET_SH1 && TARGET_DIVIDE_CALL_DIV1"
   "jsr	@%1%#"
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
@@ -2487,7 +2488,7 @@
    (clobber (reg:DF DR2_REG))
    (use (reg:PSI FPSCR_REG))
    (use (match_operand:SI 1 "arith_reg_operand" "r"))]
-  "TARGET_SH4 && ! TARGET_FPU_SINGLE"
+  "TARGET_FPU_DOUBLE && ! TARGET_FPU_SINGLE"
   "jsr	@%1%#"
   [(set_attr "type" "sfunc")
    (set_attr "fp_mode" "double")
@@ -2501,7 +2502,8 @@
    (clobber (reg:DF DR2_REG))
    (clobber (reg:SI R2_REG))
    (use (match_operand:SI 1 "arith_reg_operand" "r"))]
-  "(TARGET_HARD_SH4 || TARGET_SHCOMPACT) && TARGET_FPU_SINGLE"
+  "(TARGET_FPU_SINGLE_ONLY || TARGET_FPU_DOUBLE || TARGET_SHCOMPACT)
+   && TARGET_FPU_SINGLE"
   "jsr	@%1%#"
   [(set_attr "type" "sfunc")
    (set_attr "needs_delay_slot" "yes")])
diff --git a/gcc/config/sh/sh.opt b/gcc/config/sh/sh.opt
index 0ee36be45fa6..c314e144c21d 100644
--- a/gcc/config/sh/sh.opt
+++ b/gcc/config/sh/sh.opt
@@ -24,6 +24,10 @@ Mask(SH_E)
 ;; Set if the default precision of th FPU is single.
 Mask(FPU_SINGLE)
 
+;; Set if the a double-precision FPU is present but is restricted to
+;; single precision usage only.
+Mask(FPU_SINGLE_ONLY)
+
 ;; Set if we should generate code using type 2A insns.
 Mask(HARD_SH2A)
 
@@ -339,7 +343,7 @@ Target RejectNegative Joined UInteger Var(sh_multcost) Init(-1)
 Cost to assume for a multiply insn
 
 musermode
-Target Report RejectNegative Mask(USERMODE)
+Target Report RejectNegative Var(TARGET_USERMODE)
 Don't generate privileged-mode only code; implies -mno-inline-ic_invalidate if the inline code would not work in user mode.
 
 ;; We might want to enable this by default for TARGET_HARD_SH4, because
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1f69684fb6c0..231ceb5bd0ac 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+2013-03-13  Oleg Endo  <olegendo@gcc.gnu.org>
+
+	PR target/49880
+	* gcc.target/sh/pr49880-1.c: New.
+	* gcc.target/sh/pr49880-2.c: New.
+	* gcc.target/sh/pr49880-3.c: New.
+	* gcc.target/sh/pr49880-4.c: New.
+	* gcc.target/sh/pr49880-5.c: New.
+
 2013-03-13  Paolo Carlini  <paolo.carlini@oracle.com>
 
 	* g++.dg/cpp0x/alias-decl-32.C: Remove redundant bits.
diff --git a/gcc/testsuite/gcc.target/sh/pr49880-1.c b/gcc/testsuite/gcc.target/sh/pr49880-1.c
new file mode 100644
index 000000000000..e19f1bf38a1f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr49880-1.c
@@ -0,0 +1,22 @@
+/* Check that the option -mdiv=call-div1 works.  */
+/* { dg-do link { target "sh*-*-*" } } */
+/* { dg-options "-mdiv=call-div1" }  */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } }  */
+
+int
+test00 (int a, int b)
+{
+  return a / b;
+}
+
+unsigned int
+test01 (unsigned int a, unsigned b)
+{
+  return a / b;
+}
+
+int
+main (int argc, char** argv)
+{
+  return test00 (argc, 123) + test01 (argc, 123);
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr49880-2.c b/gcc/testsuite/gcc.target/sh/pr49880-2.c
new file mode 100644
index 000000000000..eef832e30db5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr49880-2.c
@@ -0,0 +1,22 @@
+/* Check that the option -mdiv=call-fp works.  */
+/* { dg-do link { target "sh*-*-*" } } */
+/* { dg-options "-mdiv=call-fp" }  */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } }  */
+
+int
+test00 (int a, int b)
+{
+  return a / b;
+}
+
+unsigned int
+test01 (unsigned int a, unsigned b)
+{
+  return a / b;
+}
+
+int
+main (int argc, char** argv)
+{
+  return test00 (argc, 123) + test01 (argc, 123);
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr49880-3.c b/gcc/testsuite/gcc.target/sh/pr49880-3.c
new file mode 100644
index 000000000000..80a7df548a89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr49880-3.c
@@ -0,0 +1,22 @@
+/* Check that the option -mdiv=call-table works.  */
+/* { dg-do link { target "sh*-*-*" } } */
+/* { dg-options "-mdiv=call-table" }  */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } }  */
+
+int
+test00 (int a, int b)
+{
+  return a / b;
+}
+
+unsigned int
+test01 (unsigned int a, unsigned b)
+{
+  return a / b;
+}
+
+int
+main (int argc, char** argv)
+{
+  return test00 (argc, 123) + test01 (argc, 123);
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr49880-4.c b/gcc/testsuite/gcc.target/sh/pr49880-4.c
new file mode 100644
index 000000000000..998a8b69fdd9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr49880-4.c
@@ -0,0 +1,19 @@
+/* Check that the option -mdiv=call-fp does not produce calls to the
+   library function that uses FPU to implement integer division if FPU insns
+   are not supported or are disabled.  */
+/* { dg-do compile { target "sh*-*-*" } }  */
+/* { dg-options "-mdiv=call-fp" }  */
+/* { dg-skip-if "" { "sh*-*-*" } { "*"} { "-m1" "-m2" "-m3" "-m4al" "*nofpu" "-m4-340*" "-m4-400*" "-m4-500*" } }  */
+/* { dg-final { scan-assembler-not "sdivsi3_i4\n|udivsi3_i4\n" } }  */
+
+int
+test00 (int a, int b)
+{
+  return a / b;
+}
+
+unsigned int
+test01 (unsigned int a, unsigned b)
+{
+  return a / b;
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr49880-5.c b/gcc/testsuite/gcc.target/sh/pr49880-5.c
new file mode 100644
index 000000000000..09e99a85f639
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr49880-5.c
@@ -0,0 +1,19 @@
+/* Check that the option -mdiv=call-fp results in the corresponding library
+   function calls on targets that have a double precision FPU.  */
+/* { dg-do compile { target "sh*-*-*" } }  */
+/* { dg-options "-mdiv=call-fp" }  */
+/* { dg-skip-if "" { "sh*-*-*" } { "*"} { "-m2a" "-m4" "-m4a" "*single-only" } }  */
+/* { dg-final { scan-assembler "sdivsi3_i4\n" } }  */
+/* { dg-final { scan-assembler "udivsi3_i4\n" } }  */
+
+int
+test00 (int a, int b)
+{
+  return a / b;
+}
+
+unsigned int
+test01 (unsigned int a, unsigned b)
+{
+  return a / b;
+}
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index fe08adb12aa0..61f5cc07694a 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,9 @@
+2013-03-13  Oleg Endo  <olegendo@gcc.gnu.org>
+
+	PR target/49880
+	* config/sh/lib1funcs.S (sdivsi3_i4, udivsi3_i4): Enable for SH2A.
+	(sdivsi3, udivsi3): Remove SH4 check and always compile these functions.
+
 2013-03-07  Sriraman Tallam  <tmsriram@google.com>
 
 	* config/i386/cpuinfo.c (get_intel_cpu): Fix cpuid codes for
diff --git a/libgcc/config/sh/lib1funcs.S b/libgcc/config/sh/lib1funcs.S
index 562571904215..5f0bbff264f4 100644
--- a/libgcc/config/sh/lib1funcs.S
+++ b/libgcc/config/sh/lib1funcs.S
@@ -1006,7 +1006,7 @@ hiset:	sts	macl,r0		! r0 = bb*dd
 #ifdef L_sdivsi3_i4
 	.title "SH DIVIDE"
 !! 4 byte integer Divide code for the Renesas SH
-#ifdef __SH4__
+#if defined (__SH4__) || defined (__SH2A__)
 !! args in r4 and r5, result in fpul, clobber dr0, dr2
 
 	.global	GLOBAL(sdivsi3_i4)
@@ -1021,7 +1021,7 @@ GLOBAL(sdivsi3_i4):
 	ftrc dr0,fpul
 
 	ENDFUNC(GLOBAL(sdivsi3_i4))
-#elif defined(__SH4_SINGLE__) || defined(__SH4_SINGLE_ONLY__) || (defined (__SH5__) && ! defined __SH4_NOFPU__)
+#elif defined (__SH2A_SINGLE__) || defined (__SH2A_SINGLE_ONLY__) || defined(__SH4_SINGLE__) || defined(__SH4_SINGLE_ONLY__) || (defined (__SH5__) && ! defined __SH4_NOFPU__)
 !! args in r4 and r5, result in fpul, clobber r2, dr0, dr2
 
 #if ! __SH5__ || __SH5__ == 32
@@ -1046,13 +1046,12 @@ GLOBAL(sdivsi3_i4):
 
 	ENDFUNC(GLOBAL(sdivsi3_i4))
 #endif /* ! __SH5__ || __SH5__ == 32 */
-#endif /* ! __SH4__ */
+#endif /* ! __SH4__ || __SH2A__  */
 #endif
 
 #ifdef L_sdivsi3
 /* __SH4_SINGLE_ONLY__ keeps this part for link compatibility with
    sh2e/sh3e code.  */
-#if (! defined(__SH4__) && ! defined (__SH4_SINGLE__)) || defined (__linux__)
 !!
 !! Steve Chamberlain
 !! sac@cygnus.com
@@ -1369,13 +1368,12 @@ div0:	rts
 
 	ENDFUNC(GLOBAL(sdivsi3))
 #endif /* ! __SHMEDIA__ */
-#endif /* ! __SH4__ */
 #endif
 #ifdef L_udivsi3_i4
 
 	.title "SH DIVIDE"
 !! 4 byte integer Divide code for the Renesas SH
-#ifdef __SH4__
+#if defined (__SH4__) || defined (__SH2A__)
 !! args in r4 and r5, result in fpul, clobber r0, r1, r4, r5, dr0, dr2, dr4,
 !! and t bit
 
@@ -1417,7 +1415,7 @@ L1:
 	.double 2147483648
 
 	ENDFUNC(GLOBAL(udivsi3_i4))
-#elif defined (__SH5__) && ! defined (__SH4_NOFPU__)
+#elif defined (__SH5__) && ! defined (__SH4_NOFPU__) && ! defined (__SH2A_NOFPU__)
 #if ! __SH5__ || __SH5__ == 32
 !! args in r4 and r5, result in fpul, clobber r20, r21, dr0, fr33
 	.mode	SHmedia
@@ -1438,7 +1436,7 @@ GLOBAL(udivsi3_i4):
 
 	ENDFUNC(GLOBAL(udivsi3_i4))
 #endif /* ! __SH5__ || __SH5__ == 32 */
-#elif defined(__SH4_SINGLE__) || defined(__SH4_SINGLE_ONLY__)
+#elif defined (__SH2A_SINGLE__) || defined (__SH2A_SINGLE_ONLY__) || defined(__SH4_SINGLE__) || defined(__SH4_SINGLE_ONLY__)
 !! args in r4 and r5, result in fpul, clobber r0, r1, r4, r5, dr0, dr2, dr4
 
 	.global	GLOBAL(udivsi3_i4)
@@ -1493,7 +1491,6 @@ L1:
 #ifdef L_udivsi3
 /* __SH4_SINGLE_ONLY__ keeps this part for link compatibility with
    sh2e/sh3e code.  */
-#if (! defined(__SH4__) && ! defined (__SH4_SINGLE__)) || defined (__linux__)
 
 !! args in r4 and r5, result in r0, clobbers r4, pr, and t bit
 	.global	GLOBAL(udivsi3)
@@ -1688,7 +1685,6 @@ LOCAL(large_divisor):
 
 	ENDFUNC(GLOBAL(udivsi3))
 #endif /* ! __SHMEDIA__ */
-#endif /* __SH4__ */
 #endif /* L_udivsi3 */
 
 #ifdef L_udivdi3
-- 
GitLab