Bug 19857

Summary: [4.0 Regression] alignment check of SSE constant fails in simple test program
Product: gcc Reporter: stevenj <stevenj>
Component: middle-endAssignee: Jakub Jelinek <jakub>
Status: RESOLVED FIXED    
Severity: normal CC: gcc-bugs
Priority: P2 Keywords: patch, wrong-code
Version: 4.0.0   
Target Milestone: 4.0.0   
Host: Target:
Build: Known to work: 3.3.2
Known to fail: 4.0.0 Last reconfirmed: 2005-02-10 17:21:35
Bug Depends on:    
Bug Blocks: 19858    

Description stevenj@fftw.org 2005-02-09 17:04:04 UTC
When I compile a simple test program that declares an SSE constant and checks
that it is 8-byte aligned (see below), the alignment check fails in the
gcc 4.0 snapshot (it succeeds in 3.3.5).

I'm not sure whether the constant is actually misaligned or the alignment
check itself is miscompiled...changing the check slightly makes it succeed.

Environment:
System: Linux fftw.org 2.6.3-1-686-smp #2 SMP Tue Feb 24 20:29:08 EST 2004 i686 GNU/Linux
Architecture: i686

	
host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: i686-pc-linux-gnu
configured with: ../configure --prefix=/home/stevenj/gcc4

How-To-Repeat:

Compile the following code with 'gcc -O3 -msse -o bug bug.c' and run
with './bug && echo ok' ... output *should* be "ok" (ALIGNED==true),
but is not.

(Yes, the way the alignment check is performed looks kinda weird...it
is distilled from other code (www.fftw.org), obviously...but it should
still pass for any 8-byte aligned quantity.)

Thanks for looking into this,

Steven G. Johnson


typedef float V __attribute__ ((vector_size (16)));
union fvec {
     float f[4];
     V v;
};

typedef unsigned int uintptr_t;
#define ALIGNMENT 8
#define TAINT_BIT 1
#define UNTAINT(p) ((float *) (((uintptr_t) (p)) & ~(uintptr_t)3))
#define PTRINT(p) ((uintptr_t)(p))
#define ALIGNED(p) \
  (((PTRINT(UNTAINT(p)) % ALIGNMENT) == 0) && !(PTRINT(p) & TAINT_BIT))

const union fvec foo = {{-0.0, 0.0, -0.0, 0.0}};

int main(void)
{
     return !ALIGNED(&foo);
}
Comment 1 Andrew Pinski 2005-02-09 21:24:32 UTC
Confirmed, here is a testcase which uses abort:
typedef float V __attribute__ ((vector_size (16)));
typedef __SIZE_TYPE__ uintptr_t;
V foo;
void abort (void);

int main(void)
{
  V *foo2 = &foo;
  if (!(((((uintptr_t)(((float *) (((uintptr_t) foo2) & ~(uintptr_t)3)))) % 8) == 0) && !(((uintptr_t)foo2) & 1)))
   abort ();
  return 0;
}



Comment 2 Jakub Jelinek 2005-02-10 17:21:34 UTC
This looks like fold_truthop bug, will look at it.
Comment 3 Jakub Jelinek 2005-02-10 18:07:08 UTC
Actually, I see there multiple problems elsewhere.
First is on
int i;
int foo (void)
{
  return i & ~(unsigned int)3;
}
First is that
          if (change)
            return fold (build2 (BIT_AND_EXPR, type,
                                 fold_convert (type, and0),
                                 fold_convert (type, and1)));
folds (int) ((unsigned)i & ~(unsigned)3) into i & (int)~(unsigned)3 where
(int)~(unsigned)3 is -4 with TREE_OVERFLOW set.  But there is no overflow
in the original program, so we shouldn't IMHO create one as part of this
optimization.

Another problem is that
    case POINTER_TYPE:
    case REFERENCE_TYPE:
      if (integer_zerop (expr))
        expr = integer_zero_node;
      else
        expr = fold (build1 (CONVERT_EXPR,
                             lang_hooks.types.type_for_size (POINTER_SIZE, 0),
                             expr));

      return convert_to_integer (type, expr);
unconditionally converts to signed type as wide as pointer (== intptr_t) instead
of considering TYPE_UNSIGNED (type).

As the result of these 2, fold_truthop is presented with ll_mask and ll_and_mask
TREE_OVERFLOW -4 and given that gets confused into believing the whole comparison
is always 0.
Comment 4 Jakub Jelinek 2005-02-15 11:42:18 UTC
Patch here: <http://gcc.gnu.org/ml/gcc-patches/2005-02/msg00810.html>
Comment 5 GCC Commits 2005-02-16 13:54:49 UTC
Subject: Bug 19857

CVSROOT:	/cvs/gcc
Module name:	gcc
Changes by:	jakub@gcc.gnu.org	2005-02-16 13:54:31

Modified files:
	gcc            : ChangeLog convert.c fold-const.c 
	gcc/testsuite  : ChangeLog 
Added files:
	gcc/testsuite/gcc.c-torture/execute: 20050215-1.c 
	gcc/testsuite/gcc.dg/tree-ssa: 20050215-1.c 

Log message:
	PR middle-end/19857
	* fold-const.c (fold): Don't optimize (T)(x & cst) to
	(T)x & (T)cst if (T)cst overflows.
	* convert.c (convert_to_integer) <case POINTER_TYPE>: Pass
	TYPE_UNSIGNED (type) as type_for_size's UNSIGNEDP argument.
	
	* gcc.dg/tree-ssa/20050215-1.c: New test.
	* gcc.c-torture/execute/20050215-1.c: New test.

Patches:
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&r1=2.7491&r2=2.7492
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/convert.c.diff?cvsroot=gcc&r1=1.54&r2=1.55
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/fold-const.c.diff?cvsroot=gcc&r1=1.512&r2=1.513
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&r1=1.5039&r2=1.5040
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/gcc.c-torture/execute/20050215-1.c.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/gcc.dg/tree-ssa/20050215-1.c.diff?cvsroot=gcc&r1=NONE&r2=1.1

Comment 6 Jakub Jelinek 2005-02-16 13:58:01 UTC
Fixed.