[PATCH] Fix SROA regression causing data corruption, fixes PR19250

Björn Steinbrink bsteinbr at gmail.com
Mon Jun 16 15:30:02 PDT 2014


Hi Duncan,

I seem to be unable to get the review system to add you to the list of
mail receivers. Please excuse this extra mail. I had already added the
requested comment and extra test for the order indepence last week, but
happened to re-read the commit message today and rewrote that to be
(hopefully) more correct / easier to understand. I also simplified the
original testcase a bit.

Greetings
Björn

PS: I should probably mention that I will need someone to commit this
for me as I do not have commit access.

On 2014.06.16 22:16:49 +0000, Björn Steinbrink wrote:
> Fix SROA regression causing miscompilation, fixes PR19250
> 
> Summary:
> r199771 accidently changed the logic that excludes integer types that
> are not a byte width multiple from being used as the type used for a
> newly formed partition.
> 
> This means that we can, for example, end up with a partition that spans
> a single byte and has two users, one load with type i1 and another one
> with type i32. The latter is considered to be splittable and expands
> beyond the partition.
> 
> Now in findCommonType, i1 is assigned to Ty before the check that
> rejects i1 because its width is not a byte width multiple. And because
> it is the only type that spans the whole partition, TyIsCommon remains
> true and i1 is returned as the common type.
> 
> Since such types are not actually supported, this causes some bits to be
> zeroed out in the load of the i32 value, because the first byte gets
> truncated to i1 and then zero-extended.
> 
> To fix this problem, we must make sure to check for non-byte width types
> first and always reject them.
> 
> Reviewers: dexonsmith
> Cc: aprantl
> 
> Differential Revision: http://reviews.llvm.org/D3297
> 
> http://reviews.llvm.org/D3297
> 
> Files:
>   lib/Transforms/Scalar/SROA.cpp
>   test/Transforms/SROA/order_independence.ll
>   test/Transforms/SROA/slicewidth.ll

> Index: lib/Transforms/Scalar/SROA.cpp
> ===================================================================
> --- lib/Transforms/Scalar/SROA.cpp
> +++ lib/Transforms/Scalar/SROA.cpp
> @@ -1032,11 +1032,6 @@
>        UserTy = SI->getValueOperand()->getType();
>      }
>  
> -    if (!UserTy || (Ty && Ty != UserTy))
> -      TyIsCommon = false; // Give up on anything but an iN type.
> -    else
> -      Ty = UserTy;
> -
>      if (IntegerType *UserITy = dyn_cast_or_null<IntegerType>(UserTy)) {
>        // If the type is larger than the partition, skip it. We only encounter
>        // this for split integer operations where we want to use the type of the
> @@ -1051,6 +1046,13 @@
>        if (!ITy || ITy->getBitWidth() < UserITy->getBitWidth())
>          ITy = UserITy;
>      }
> +
> +    // To keep thing independent from the order of slices, Ty and TyIsCommon
> +    // must not depend on types skipped above
> +    if (!UserTy || (Ty && Ty != UserTy))
> +      TyIsCommon = false; // Give up on anything but an iN type.
> +    else
> +      Ty = UserTy;
>    }
>  
>    return TyIsCommon ? Ty : ITy;
> Index: test/Transforms/SROA/order_independence.ll
> ===================================================================
> --- /dev/null
> +++ test/Transforms/SROA/order_independence.ll
> @@ -0,0 +1,38 @@
> +; RUN: opt < %s -sroa -S | FileCheck %s
> +target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
> +
> +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32, i1) nounwind
> +
> +; Check that the chosen type for a split is independent from the order of
> +; slices even in case of types that are skipped because their width is not a
> +; byte width multiple
> +
> +define void @skipped_inttype_first({ i16*, i32 }*) {
> +; CHECK-LABEL: @skipped_inttype_first
> +; CHECK: alloca i8*
> +  %arg = alloca { i16*, i32 }, align 8
> +  %2 = bitcast { i16*, i32 }* %0 to i8*
> +  %3 = bitcast { i16*, i32 }* %arg to i8*
> +  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %3, i8* %2, i32 16, i32 8, i1 false)
> +  %b = getelementptr inbounds { i16*, i32 }* %arg, i64 0, i32 0
> +  %pb0 = bitcast i16** %b to i63*
> +  %b0 = load i63* %pb0
> +  %pb1 = bitcast i16** %b to i8**
> +  %b1 = load i8** %pb1
> +  ret void
> +}
> +
> +define void @skipped_inttype_last({ i16*, i32 }*) {
> +; CHECK-LABEL: @skipped_inttype_last
> +; CHECK: alloca i8*
> +  %arg = alloca { i16*, i32 }, align 8
> +  %2 = bitcast { i16*, i32 }* %0 to i8*
> +  %3 = bitcast { i16*, i32 }* %arg to i8*
> +  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %3, i8* %2, i32 16, i32 8, i1 false)
> +  %b = getelementptr inbounds { i16*, i32 }* %arg, i64 0, i32 0
> +  %pb1 = bitcast i16** %b to i8**
> +  %b1 = load i8** %pb1
> +  %pb0 = bitcast i16** %b to i63*
> +  %b0 = load i63* %pb0
> +  ret void
> +}
> Index: test/Transforms/SROA/slicewidth.ll
> ===================================================================
> --- /dev/null
> +++ test/Transforms/SROA/slicewidth.ll
> @@ -0,0 +1,25 @@
> +; RUN: opt < %s -sroa -S | FileCheck %s
> +target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
> +
> +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32, i1) nounwind
> +
> +define void @no_split_on_non_byte_width(i32) {
> +; This tests that allocas are not split into slices that are not byte width multiple
> +  %arg = alloca i32 , align 8
> +  store i32 %0, i32* %arg
> +  br label %load_i32
> +
> +load_i32:
> +; CHECK-LABEL: load_i32:
> +; CHECK-NOT: bitcast {{.*}} to i1
> +; CHECK-NOT: zext i1
> +  %r0 = load i32* %arg
> +  br label %load_i1
> +
> +load_i1:
> +; CHECK-LABEL: load_i1:
> +; CHECK: bitcast {{.*}} to i1
> +  %p1 = bitcast i32* %arg to i1*
> +  %t1 = load i1* %p1
> +  ret void
> +}




More information about the llvm-commits mailing list