[LLVMbugs] [Bug 2823] New: llvm-gcc does not respect ABI alignment for structs-with-vectors
bugzilla-daemon at cs.uiuc.edu
bugzilla-daemon at cs.uiuc.edu
Tue Sep 23 03:08:53 PDT 2008
http://llvm.org/bugs/show_bug.cgi?id=2823
Summary: llvm-gcc does not respect ABI alignment for structs-
with-vectors
Product: new-bugs
Version: unspecified
Platform: PC
OS/Version: Linux
Status: NEW
Severity: normal
Priority: P2
Component: new bugs
AssignedTo: unassignedbugs at nondot.org
ReportedBy: matthijs at stdin.nl
CC: llvmbugs at cs.uiuc.edu
The below program contains a struct that contains a single vector of 4 i32's.
When llvm-gcc generates alloca's for this struct, the alignment gets set to 4,
while the ABI alignment of the contained vector is 16. Since the program passes
the contained vector to another function, this violates alignment requirements.
The same goes for a union containing a vector, as illustrated in the main2
function.
Since the div function assumes that it's arguments are ABI aligned, llc will
generate aligned SSE instructions (movaps) operating on the function arguments.
Since the caller does not respect the required alignment, this segfaults.
$ llvm-gcc align.c -S -emit-llvm -o - | llvm-as | llc -o align.S
$ gcc align.S
$ ./a.out
Segmentation fault (core dumped)
In most cases, this behaviour is not observed, since instcombine will change
the type of an alloca when it is bitcasted to something with a higher
alignment. Since we're not running instcombine (this example would require
inlining as well), the bug is not masked off. This example is mostly based on
the test-suite/SingleSource/UnitTests/Vector/divide.c file, since that crashed
with a local modification to make instcombine not change alloca instructions in
some cases.
Note that when changing the below example to not use a seperate div function,
but doing the dividing inline, the vector loads will be generated with a
conservative alignment of 1, llc will use unaligned SSE instructions (movups)
and everything works fine.
On a related note, clang does do the right thing, and produces the alloca's
with the correct alignment right away.
So, here's the code:
typedef unsigned uvec __attribute__ ((__vector_size__ (16)));
static void div(uvec *A, uvec *B, uvec *R) { *R = *A / *B; }
typedef union {
uvec V;
unsigned A[4];
} UV;
typedef struct {
uvec V;
} SV;
int main(int argc, char**argv) {
SV V;
div (&V.V, &V.V, &V.V);
return (unsigned)&V.V;
}
int main2(int argc, char**argv) {
UV V;
div (&V.V, &V.V, &V.V);
return (unsigned)&V.V;
}
Which produces (main2 function left out):
; ModuleID = 'align.c'
target datalayout =
"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
target triple = "i386-pc-linux-gnu"
%struct.SV = type <{ <4 x i32> }>
%struct.UV = type <{ <4 x i32> }>
define internal void @div(<4 x i32>* %A, <4 x i32>* %B, <4 x i32>* %R) nounwind
{
entry:
%A_addr = alloca <4 x i32>* ; <<4 x i32>**> [#uses=2]
%B_addr = alloca <4 x i32>* ; <<4 x i32>**> [#uses=2]
%R_addr = alloca <4 x i32>* ; <<4 x i32>**> [#uses=2]
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
store <4 x i32>* %A, <4 x i32>** %A_addr
store <4 x i32>* %B, <4 x i32>** %B_addr
store <4 x i32>* %R, <4 x i32>** %R_addr
%0 = load <4 x i32>** %A_addr, align 4 ; <<4 x i32>*>
[#uses=1]
%1 = load <4 x i32>* %0, align 16 ; <<4 x i32>> [#uses=1]
%2 = load <4 x i32>** %B_addr, align 4 ; <<4 x i32>*>
[#uses=1]
%3 = load <4 x i32>* %2, align 16 ; <<4 x i32>> [#uses=1]
%4 = udiv <4 x i32> %1, %3 ; <<4 x i32>> [#uses=1]
%5 = load <4 x i32>** %R_addr, align 4 ; <<4 x i32>*>
[#uses=1]
store <4 x i32> %4, <4 x i32>* %5, align 16
br label %return
return: ; preds = %entry
ret void
}
define i32 @main(i32 %argc, i8** %argv) nounwind {
entry:
%argc_addr = alloca i32 ; <i32*> [#uses=1]
%argv_addr = alloca i8** ; <i8***> [#uses=1]
%retval = alloca i32 ; <i32*> [#uses=2]
%V = alloca %struct.SV, align 4 ; <%struct.SV*> [#uses=4]
%0 = alloca i32 ; <i32*> [#uses=2]
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
store i32 %argc, i32* %argc_addr
store i8** %argv, i8*** %argv_addr
%1 = getelementptr %struct.SV* %V, i32 0, i32 0 ; <<4 x i32>*>
[#uses=1]
%2 = getelementptr %struct.SV* %V, i32 0, i32 0 ; <<4 x i32>*>
[#uses=1]
%3 = getelementptr %struct.SV* %V, i32 0, i32 0 ; <<4 x i32>*>
[#uses=1]
call void @div(<4 x i32>* %1, <4 x i32>* %2, <4 x i32>* %3) nounwind
%4 = getelementptr %struct.SV* %V, i32 0, i32 0 ; <<4 x i32>*>
[#uses=1]
%5 = ptrtoint <4 x i32>* %4 to i32 ; <i32> [#uses=1]
store i32 %5, i32* %0, align 4
%6 = load i32* %0, align 4 ; <i32> [#uses=1]
store i32 %6, i32* %retval, align 4
br label %return
return: ; preds = %entry
%retval1 = load i32* %retval ; <i32> [#uses=1]
ret i32 %retval1
}
--
Configure bugmail: http://llvm.org/bugs/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.
More information about the llvm-bugs
mailing list