This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug tree-optimization/33383] [4.3 Regression] Revision 128092 miscompiles 400.perlbench
- From: "jakub at gcc dot gnu dot org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 15 Oct 2007 11:20:19 -0000
- Subject: [Bug tree-optimization/33383] [4.3 Regression] Revision 128092 miscompiles 400.perlbench
- References: <bug-33383-682@http.gcc.gnu.org/bugzilla/>
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
------- Comment #13 from jakub at gcc dot gnu dot org 2007-10-15 11:20 -------
To me this looks like aliasing violation in 400.perlbench (and in perl 5.8.8
too, so I'll cite the latter).
#define IVTYPE long /**/
typedef IVTYPE IV;
typedef struct xpviv XPVIV;
typedef size_t STRLEN;
struct xpviv {
char * xpv_pv; /* pointer to malloced string */
STRLEN xpv_cur; /* length of xpv_pv as a C string */
STRLEN xpv_len; /* allocated size */
IV xiv_iv; /* integer value or pv offset */
};
# define STRUCT_OFFSET(s,m) (Size_t)(&(((s *)0)->m))
#define STATIC static
# define pTHX_
# define LOCK_SV_MUTEX
# define UNLOCK_SV_MUTEX
extern IV * PL_xiv_root;
In sv.c, we have:
STATIC void
S_del_xiv(pTHX_ XPVIV *p)
{
IV* xiv = (IV*)((char*)(p) + STRUCT_OFFSET(XPVIV, xiv_iv));
LOCK_SV_MUTEX;
*(IV**)xiv = PL_xiv_root;
PL_xiv_root = xiv;
UNLOCK_SV_MUTEX;
}
The problem is when Perl_sv_upgrade function is called, with (sv->sv_flags &
0xff) == SVt_IV, mt == SVt_PVNV, ((XPVIV*) (sv)->sv_any)->xiv_iv == 0 and
PL_xiv_root != NULL:
IV iv;
...
switch (SvTYPE(sv)) {
case SVt_NULL:
break;
case SVt_IV:
iv = SvIVX(sv);
del_XIV(SvANY(sv));
if (mt == SVt_NV)
mt = SVt_PVNV;
else if (mt < SVt_PVIV)
mt = SVt_PVIV;
break;
...
switch (mt) {
case SVt_PVNV:
SvANY(sv) = new_XPVNV();
SvPV_set(sv, pv);
SvCUR_set(sv, cur);
SvLEN_set(sv, len);
SvIV_set(sv, iv);
SvNV_set(sv, nv);
break;
...
or better preprocessed:
switch (((sv)->sv_flags & 0xff)) {
case SVt_NULL:
break;
case SVt_IV:
iv = ((XPVIV*) (sv)->sv_any)->xiv_iv;
S_del_xiv((XPVIV*) (sv)->sv_any);
if (mt == SVt_NV)
mt = SVt_PVNV;
else if (mt < SVt_PVIV)
mt = SVt_PVIV;
break;
...
switch (mt) {
...
case SVt_PVNV:
(sv)->sv_any = (void*)S_new_xpvnv();
((XPV*) (sv)->sv_any)->xpv_pv = pv;
((XPV*) (sv)->sv_any)->xpv_cur = cur;
((XPV*) (sv)->sv_any)->xpv_len = len;
((XPVIV*) (sv)->sv_any)->xiv_iv = iv;
((XPVNV*)(sv)->sv_any)->xnv_nv = nv;
break;
when sv.c is compiled with -O2 -fstrict-aliasing, then the
*(IV**)xiv = PL_xiv_root; write isn't considered aliased with the
iv = ((XPVIV*) (sv)->sv_any)->xiv_iv;, because the former accesses the object
as long *, while the latter as long. The difference between -O2
-fstrict-aliasing and -O2 -fno-strict-aliasing compiled sv.c is then that
in this call ((XPVIV*) (sv)->sv_any)->xiv_iv = iv; stores (long) PL_xiv_root
value before entering this function with -fstrict-aliasing and 0 (i.e. what
((XPVIV*) (sv)->sv_any)->xiv_iv contained on function entry) with
-fno-strict-aliasing.
It seems perl is aware of this, but doesn't care to fix it - Configure has
instead:
case "$gccversion" in
1*) ;;
2.[0-8]*) ;;
?*) echo " "
echo "Checking if your compiler accepts -fno-strict-aliasing" 2
>&1
echo 'int main(void) { return 0; }' > gcctest.c
if $cc -O2 -fno-strict-aliasing -o gcctest gcctest.c; then
echo "Yes, it does." 2>&1
case "$ccflags" in
*strict-aliasing*)
echo "Leaving current flags $ccflags alone." 2>
&1
;;
*) dflt="$dflt -fno-strict-aliasing" ;;
esac
else
echo "Nope, it doesn't, but that's ok." 2>&1
fi
;;
esac
Not sure what is the best way forward with CPU2006 and GCC though (and what are
other compilers doing to pass 400.perlbench). Is it acceptable to add
-fno-strict-aliasing just for this test?
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33383