This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Fix PR target/38287
- From: Eric Botcazou <ebotcazou at adacore dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 30 Nov 2008 20:25:25 +0100
- Subject: Fix PR target/38287
This is a miscompilation of Qt 3 at -O2 -fPIC on SPARC/Linux, a regression
present in all 4.x compilers. The problem is also reproducible on Solaris
with -mcpu=v8.
It is triggered by a bad interaction between reload and the register window
feature of the SPARC. On this architecture, eliminating the soft FP to the
SP instead of the hard FP means not changing the register window and thus
severely restricting the set of registers that can be used in the function
(called leaf in that case); in particular, the PIC register cannot be used.
One of the functions in the testcase was deemed eligible to this elimination
up to reload. The problem is that it contains a udivsi3_sp32 instruction
(define_insn "udivsi3_sp32"
[(set (match_operand:SI 0 "register_operand" "=r,&r,&r")
(udiv:SI (match_operand:SI 1 "nonimmediate_operand" "r,r,m")
(match_operand:SI 2 "input_operand" "rI,m,r")))]
"(TARGET_V8 || TARGET_DEPRECATED_V8_INSNS)
whose operand #2 is 86400000. This operand is an input_operand because it is
suitable for a sethi instruction, but it doesn't satisfy the 'I' constraint.
So reload needed to put it into the constant pool, thus creating an access to
the data, hence a use of the PIC register, eventually preventing the function
from being leaf. But the soft FP had already been eliminated to the SP at
this point so, in the end, the function was emitted non-leaf but with bogus
memory accesses based on %sp instead of %fp.
Fixed by adding a new alternative with constraint 'K' for operand #2 to the
pattern as well as its counterpart divsi3_sp32. The patch also adds the
missing TARGET_V9 case to the pattern (it was already there for divsi3_sp32).
Tested on sparc-solaris2.10 (default) and sparc-sun-solaris2.9 (with-cpu=v8),
applied on all branches.
2008-11-30 Eric Botcazou <ebotcazou@adacore.com>
PR target/38287
* config/sparc/sparc.md (divsi3 expander): Remove constraints.
(divsi3_sp32): Add new alternative with 'K' for operand #2.
(cmp_sdiv_cc_set): Factor common string.
(udivsi3_sp32): Add new alternative with 'K' for operand #2.
Add TARGET_V9 case.
(cmp_udiv_cc_set): Factor common string.
2008-11-30 Eric Botcazou <ebotcazou@adacore.com>
* g++.dg/opt/reload3.C: New test.
--
Eric Botcazou
Index: config/sparc/sparc.md
===================================================================
--- config/sparc/sparc.md (revision 142273)
+++ config/sparc/sparc.md (working copy)
@@ -4895,14 +4895,11 @@ (define_insn "const_umulsi3_highpart"
[(set_attr "type" "multi")
(set_attr "length" "2")])
-;; The V8 architecture specifies that there must be 3 instructions between
-;; a Y register write and a use of it for correct results.
-
(define_expand "divsi3"
- [(parallel [(set (match_operand:SI 0 "register_operand" "=r,r")
- (div:SI (match_operand:SI 1 "register_operand" "r,r")
- (match_operand:SI 2 "input_operand" "rI,m")))
- (clobber (match_scratch:SI 3 "=&r,&r"))])]
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (div:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "input_operand" "")))
+ (clobber (match_scratch:SI 3 ""))])]
"TARGET_V8 || TARGET_DEPRECATED_V8_INSNS"
{
if (TARGET_ARCH64)
@@ -4915,24 +4912,40 @@ (define_expand "divsi3"
}
})
+;; The V8 architecture specifies that there must be at least 3 instructions
+;; between a write to the Y register and a use of it for correct results.
+;; We try to fill one of them with a simple constant or a memory load.
+
(define_insn "divsi3_sp32"
- [(set (match_operand:SI 0 "register_operand" "=r,r")
- (div:SI (match_operand:SI 1 "register_operand" "r,r")
- (match_operand:SI 2 "input_operand" "rI,m")))
- (clobber (match_scratch:SI 3 "=&r,&r"))]
- "(TARGET_V8 || TARGET_DEPRECATED_V8_INSNS)
- && TARGET_ARCH32"
-{
- if (which_alternative == 0)
- if (TARGET_V9)
- return "sra\t%1, 31, %3\n\twr\t%3, 0, %%y\n\tsdiv\t%1, %2, %0";
- else
- return "sra\t%1, 31, %3\n\twr\t%3, 0, %%y\n\tnop\n\tnop\n\tnop\n\tsdiv\t%1, %2, %0";
- else
- if (TARGET_V9)
- return "sra\t%1, 31, %3\n\twr\t%3, 0, %%y\n\tld\t%2, %3\n\tsdiv\t%1, %3, %0";
- else
- return "sra\t%1, 31, %3\n\twr\t%3, 0, %%y\n\tld\t%2, %3\n\tnop\n\tnop\n\tsdiv\t%1, %3, %0";
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (div:SI (match_operand:SI 1 "register_operand" "r,r,r")
+ (match_operand:SI 2 "input_operand" "rI,K,m")))
+ (clobber (match_scratch:SI 3 "=&r,&r,&r"))]
+ "(TARGET_V8 || TARGET_DEPRECATED_V8_INSNS) && TARGET_ARCH32"
+{
+ output_asm_insn ("sra\t%1, 31, %3", operands);
+ output_asm_insn ("wr\t%3, 0, %%y", operands);
+
+ switch (which_alternative)
+ {
+ case 0:
+ if (TARGET_V9)
+ return "sdiv\t%1, %2, %0";
+ else
+ return "nop\n\tnop\n\tnop\n\tsdiv\t%1, %2, %0";
+ case 1:
+ if (TARGET_V9)
+ return "sethi\t%%hi(%a2), %3\n\tsdiv\t%1, %3, %0";
+ else
+ return "sethi\t%%hi(%a2), %3\n\tnop\n\tnop\n\tsdiv\t%1, %3, %0";
+ case 2:
+ if (TARGET_V9)
+ return "ld\t%2, %3\n\tsdiv\t%1, %3, %0";
+ else
+ return "ld\t%2, %3\n\tnop\n\tnop\n\tsdiv\t%1, %3, %0";
+ default:
+ gcc_unreachable ();
+ }
}
[(set_attr "type" "multi")
(set (attr "length")
@@ -4967,10 +4980,13 @@ (define_insn "*cmp_sdiv_cc_set"
(clobber (match_scratch:SI 3 "=&r"))]
"TARGET_V8 || TARGET_DEPRECATED_V8_INSNS"
{
+ output_asm_insn ("sra\t%1, 31, %3", operands);
+ output_asm_insn ("wr\t%3, 0, %%y", operands);
+
if (TARGET_V9)
- return "sra\t%1, 31, %3\n\twr\t%3, 0, %%y\n\tsdivcc\t%1, %2, %0";
+ return "sdivcc\t%1, %2, %0";
else
- return "sra\t%1, 31, %3\n\twr\t%3, 0, %%y\n\tnop\n\tnop\n\tnop\n\tsdivcc\t%1, %2, %0";
+ return "nop\n\tnop\n\tnop\n\tsdivcc\t%1, %2, %0";
}
[(set_attr "type" "multi")
(set (attr "length")
@@ -4985,29 +5001,48 @@ (define_expand "udivsi3"
"TARGET_V8 || TARGET_DEPRECATED_V8_INSNS"
"")
-;; The V8 architecture specifies that there must be 3 instructions between
-;; a Y register write and a use of it for correct results.
+;; The V8 architecture specifies that there must be at least 3 instructions
+;; between a write to the Y register and a use of it for correct results.
+;; We try to fill one of them with a simple constant or a memory load.
(define_insn "udivsi3_sp32"
- [(set (match_operand:SI 0 "register_operand" "=r,&r,&r")
- (udiv:SI (match_operand:SI 1 "nonimmediate_operand" "r,r,m")
- (match_operand:SI 2 "input_operand" "rI,m,r")))]
- "(TARGET_V8 || TARGET_DEPRECATED_V8_INSNS)
- && TARGET_ARCH32"
+ [(set (match_operand:SI 0 "register_operand" "=r,&r,&r,&r")
+ (udiv:SI (match_operand:SI 1 "nonimmediate_operand" "r,r,r,m")
+ (match_operand:SI 2 "input_operand" "rI,K,m,r")))]
+ "(TARGET_V8 || TARGET_DEPRECATED_V8_INSNS) && TARGET_ARCH32"
{
- output_asm_insn ("wr\t%%g0, %%g0, %%y", operands);
+ output_asm_insn ("wr\t%%g0, 0, %%y", operands);
+
switch (which_alternative)
{
- default:
- return "nop\n\tnop\n\tnop\n\tudiv\t%1, %2, %0";
+ case 0:
+ if (TARGET_V9)
+ return "udiv\t%1, %2, %0";
+ else
+ return "nop\n\tnop\n\tnop\n\tudiv\t%1, %2, %0";
case 1:
- return "ld\t%2, %0\n\tnop\n\tnop\n\tudiv\t%1, %0, %0";
+ if (TARGET_V9)
+ return "sethi\t%%hi(%a2), %0\n\tudiv\t%1, %0, %0";
+ else
+ return "sethi\t%%hi(%a2), %0\n\tnop\n\tnop\n\tudiv\t%1, %0, %0";
case 2:
- return "ld\t%1, %0\n\tnop\n\tnop\n\tudiv\t%0, %2, %0";
+ if (TARGET_V9)
+ return "ld\t%2, %0\n\tudiv\t%1, %0, %0";
+ else
+ return "ld\t%2, %0\n\tnop\n\tnop\n\tudiv\t%1, %0, %0";
+ case 3:
+ if (TARGET_V9)
+ return "ld\t%1, %0\n\tudiv\t%0, %2, %0";
+ else
+ return "ld\t%1, %0\n\tnop\n\tnop\n\tudiv\t%0, %2, %0";
+ default:
+ gcc_unreachable ();
}
}
[(set_attr "type" "multi")
- (set_attr "length" "5")])
+ (set (attr "length")
+ (if_then_else (eq_attr "isa" "v9")
+ (const_int 3) (const_int 5)))])
(define_insn "udivsi3_sp64"
[(set (match_operand:SI 0 "register_operand" "=r")
@@ -5033,13 +5068,14 @@ (define_insn "*cmp_udiv_cc_set"
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
(udiv:SI (match_dup 1) (match_dup 2)))]
- "TARGET_V8
- || TARGET_DEPRECATED_V8_INSNS"
+ "TARGET_V8 || TARGET_DEPRECATED_V8_INSNS"
{
+ output_asm_insn ("wr\t%%g0, 0, %%y", operands);
+
if (TARGET_V9)
- return "wr\t%%g0, %%g0, %%y\n\tudivcc\t%1, %2, %0";
+ return "udivcc\t%1, %2, %0";
else
- return "wr\t%%g0, %%g0, %%y\n\tnop\n\tnop\n\tnop\n\tudivcc\t%1, %2, %0";
+ return "nop\n\tnop\n\tnop\n\tudivcc\t%1, %2, %0";
}
[(set_attr "type" "multi")
(set (attr "length")
// PR target/38287
// { dg-do run }
// { dg-options "-O2 -mcpu=v8 -fPIC" { target { { sparc*-*-* } && { ilp32 && fpic } } } }
#include <cstdlib>
class QTime
{
public:
explicit QTime(int ms = 0) : ds(ms) {}
static QTime currentTime() { return QTime(); }
QTime addMSecs(int ms) const;
int msecs() const { return ds; }
private:
unsigned ds;
};
static const unsigned MSECS_PER_DAY = 86400000;
QTime QTime::addMSecs(int ms) const
{
QTime t;
if ( ms < 0 ) {
// % not well-defined for -ve, but / is.
int negdays = (MSECS_PER_DAY-ms) / MSECS_PER_DAY;
t.ds = ((int)ds + ms + negdays*MSECS_PER_DAY)
% MSECS_PER_DAY;
} else {
t.ds = ((int)ds + ms) % MSECS_PER_DAY;
}
return t;
}
int main()
{
if (QTime(1).addMSecs(1).msecs() != 2)
abort ();
return 0;
}