summaryrefslogtreecommitdiff
path: root/patches/gcc/3.3/sh4-kaz-workaround.patch
blob: 189b1323204c31fafb1f4e4e343b3946c889321d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
[lightly edited to fit my patch directory - dank]

From: kaz Kojima <kkojima@rr.iij4u.or.jp>
Date: Sat, 09 Aug 2003 09:46:21 +0900
To: dank@kegel.com

Hi Dan,

I've come back from the vacation and looked glibc string test
failures on sh4. This looks a gcc problem. gcc-3.3/3.4 doesn't
compile these tests correctly. The attached testcase aborts on
gcc-3.3/3.4 -O2 but exits normally gcc-3.2 and gcc-3.0.
The option -O2 is not essential but it makes the testcase small.
The failed string tests include the same pattern of the code with
f=random to generate ramdom strings but they get strings with
embedded NULL characters :-(

...
I've got a workaround below for this bug, though it might merely
paper over the real bug. Anyway, I'd like to send a PR for this.

Regards,
	kaz
--
int val = 0xff00;

int f (void) { return val; }

unsigned char a[1];

void
foo (void)
{
  a[0] = f () & 255;

  if (!a[0])
    a[0] = f () & 255;

  if (!a[0])
    a[0] = 1 + (f () & 127);
}

int
main (int argc, char **argv)
{
  foo ();
  if (!a[0])
    abort ();

  return 0;
}

--

diff -u3prN ORIG/gcc/gcc/config/sh/sh.c LOCAL/gcc/gcc/config/sh/sh.c
--- gcc/gcc/config/sh/sh.c.old	Fri Aug  8 18:39:02 2003
+++ gcc/gcc/config/sh/sh.c	Fri Aug  8 22:31:02 2003
@@ -6657,6 +6657,19 @@ arith_reg_dest (op, mode)
   return arith_reg_operand (op, mode);
 }
 
+/* Like above, but for SImode compare destinations: forbid paradoxical
+   subregs, because it would get the combiner confused.  */
+int
+arith_reg_cmp_dest (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode == SImode && GET_CODE (op) == SUBREG
+      && GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))) < 4)
+    return 0;
+  return arith_reg_operand (op, mode);
+}
+
 int
 int_gpr_dest (op, mode)
      rtx op;
diff -u3prN ORIG/gcc/gcc/config/sh/sh.h LOCAL/gcc/gcc/config/sh/sh.h
--- gcc/gcc/config/sh/sh.h.old	Fri Aug  8 18:39:02 2003
+++ gcc/gcc/config/sh/sh.h	Fri Aug  8 22:31:02 2003
@@ -3365,6 +3365,7 @@ extern int rtx_equal_function_value_matt
   {"and_operand", {SUBREG, REG, CONST_INT}},				\
   {"any_register_operand", {SUBREG, REG}},				\
   {"arith_operand", {SUBREG, REG, CONST_INT}},				\
+  {"arith_reg_cmp_dest", {SUBREG, REG}},				\
   {"arith_reg_dest", {SUBREG, REG}},					\
   {"arith_reg_operand", {SUBREG, REG}},					\
   {"arith_reg_or_0_operand", {SUBREG, REG, CONST_INT, CONST_VECTOR}},	\

--- gcc-3.3/gcc/config/sh/sh.md.orig	Tue Apr 15 10:06:10 2003
+++ gcc-3.3/gcc/config/sh/sh.md	Sat Aug  9 22:31:13 2003
@@ -616,7 +616,7 @@
 
 (define_insn ""
   [(set (reg:SI T_REG)
-	(eq:SI (and:SI (match_operand:SI 0 "arith_reg_operand" "z,r")
+	(eq:SI (and:SI (match_operand:SI 0 "arith_reg_cmp_dest" "z,r")
 		       (match_operand:SI 1 "arith_operand" "L,r"))
 	       (const_int 0)))]
   "TARGET_SH1"
@@ -631,7 +631,7 @@
 
 (define_insn "cmpeqsi_t"
   [(set (reg:SI T_REG)
-	(eq:SI (match_operand:SI 0 "arith_reg_operand" "r,z,r")
+	(eq:SI (match_operand:SI 0 "arith_reg_cmp_dest" "r,z,r")
 	       (match_operand:SI 1 "arith_operand" "N,rI,r")))]
   "TARGET_SH1"
   "@
@@ -642,7 +642,7 @@
 
 (define_insn "cmpgtsi_t"
   [(set (reg:SI T_REG)
-	(gt:SI (match_operand:SI 0 "arith_reg_operand" "r,r")
+	(gt:SI (match_operand:SI 0 "arith_reg_cmp_dest" "r,r")
 	       (match_operand:SI 1 "arith_reg_or_0_operand" "r,N")))]
   "TARGET_SH1"
   "@
@@ -652,7 +652,7 @@
 
 (define_insn "cmpgesi_t"
   [(set (reg:SI T_REG)
-	(ge:SI (match_operand:SI 0 "arith_reg_operand" "r,r")
+	(ge:SI (match_operand:SI 0 "arith_reg_cmp_dest" "r,r")
 	       (match_operand:SI 1 "arith_reg_or_0_operand" "r,N")))]
   "TARGET_SH1"
   "@
@@ -666,7 +666,7 @@
 
 (define_insn "cmpgeusi_t"
   [(set (reg:SI T_REG)
-	(geu:SI (match_operand:SI 0 "arith_reg_operand" "r")
+	(geu:SI (match_operand:SI 0 "arith_reg_cmp_dest" "r")
 		(match_operand:SI 1 "arith_reg_operand" "r")))]
   "TARGET_SH1"
   "cmp/hs	%1,%0"
@@ -674,7 +674,7 @@
 
 (define_insn "cmpgtusi_t"
   [(set (reg:SI T_REG)
-	(gtu:SI (match_operand:SI 0 "arith_reg_operand" "r")
+	(gtu:SI (match_operand:SI 0 "arith_reg_cmp_dest" "r")
 		(match_operand:SI 1 "arith_reg_operand" "r")))]
   "TARGET_SH1"
   "cmp/hi	%1,%0"