[LLVMdev] Strange pointer aliasing behaviour

Pierre C lists at peufeu.com
Wed Jun 16 13:39:14 PDT 2010


I'm hitting a strange pointer aliasing "bug". Here is a test case :

/* SOURCE CODE */

#define little_list_size 8

class LittleList1 {
public:
	int	_length;
	double	_data[ little_list_size ];

	LittleList1( int length )
	{
		_length = length;
		for( int i=0; i<length; i++ )
			_data[i] = 0;
	}
};

class LittleList2 {
public:
	int	_length;
	double	_data[ little_list_size ];

	LittleList2( int length )
	{
		_length = length;
		for( int i=0; i<_length; i++ )
			_data[i] = 0;
	}
};

int func1()
{
	LittleList1 l(4);
	return l._length;
}

int func2()
{
	LittleList2 l(4);
	return l._length;
}

/* END SOURCE CODE */

The only difference between the 2 classes is in the constructor, in the  
line :
	for( int i=0; i<_length; i++ )

One has "length" which is a function parameter, the other has "_length"  
which is the class member which was initialized in the same constructor.

Now let's compile and optimize :

llvm-g++ -emit-llvm -Winline -O3 -Iinclude  -c test2.cpp -o test2.bc
opt -S -O3 -print-alias-sets -count-aa test2.bc

Result :

%struct.LittleList1 = type { i32, [8 x double] }

********
Here, func1() is perfectly optimized :
********

define i32 @_Z5func1v() nounwind readnone {
entry:
   ret i32 4
}


********
func2() should give the exact same result as func1, however ...

Alias Set Tracker: 1 alias sets for 2 pointer values.
   AliasSet[0x0x8ca140,2] may alias, Mod/Ref   Pointers: (i32* %0, 4),  
(double* %scevgep.i, 8)

A spurious alias comes up between the 2 fields of the struct (which should  
in theory not happen).
So, it reloads _length at each iteration, thus no optimization takes place  
and the code below is generated :

********

define i32 @_Z5func2v() nounwind readnone {
entry:
   %l = alloca %struct.LittleList1, align 8        ; <%struct.LittleList1*>  
[#uses=2]
   %0 = getelementptr inbounds %struct.LittleList1* %l, i64 0, i32 0 ;  
<i32*> [#uses=2]
   store i32 4, i32* %0, align 8
   br label %bb.i

bb.i:                                             ; preds = %bb.i, %entry
   %indvar.i = phi i64 [ %tmp, %bb.i ], [ 0, %entry ] ; <i64> [#uses=2]
   %tmp = add i64 %indvar.i, 1                     ; <i64> [#uses=2]
   %tmp2.i = trunc i64 %tmp to i32                 ; <i32> [#uses=1]
   %scevgep.i = getelementptr %struct.LittleList1* %l, i64 0, i32 1, i64  
%indvar.i ; <double*> [#uses=1]
   store double 0.000000e+00, double* %scevgep.i, align 8
   %1 = load i32* %0, align 8                      ; <i32> [#uses=2]
   %2 = icmp sgt i32 %1, %tmp2.i                   ; <i1> [#uses=1]
   br i1 %2, label %bb.i, label %_ZN11LittleList2C1Ei.exit

_ZN11LittleList2C1Ei.exit:                        ; preds = %bb.i
   ret i32 %1

********

g++ correctly resolves this alias and both functions are compiled to  
"return 4".
llvm-gcc (and opt) detect a spurious alias on func2() (all alias passes  
seem to do the same here) which prevents optimizations, and in other cases  
more complex than this simple test, it also prevents loop unrolling and  
many other optimizations.

Can I do something to fix this ?





More information about the llvm-dev mailing list