[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