[PATCH] SROA: Handle a case of store size being smaller than allocation size

Thomas Jablin tjablin at gmail.com
Thu Aug 21 16:03:18 PDT 2014


I think this patch might not be the right approach. The underlying issue is
that clang translates:

union U { long m0[3]; long double m1; };

to:

%union.U = type { x86_fp80, [16 x i8] }

The x86_fp80 type is 10 bytes of data aligned to 16 bytes. Is it
permissible to copy only the lower 10 bytes of an x86_fp80? I think the
answer should be yes. This is the behavior of the underlying x87 fldt and
fstpt instructions. If copying only the lower 10 bytes of a x86_fp80 is
permissible, then the C union was not correctly lowered to LLVM IR. I think
the correct resolution is to lower the union to:

%union.U = type { [4 x i64] }




On Thu, Aug 21, 2014 at 4:37 PM, Reid Kleckner <rnk at google.com> wrote:

> Hi chandlerc,
>
> In this case, we are creating an x86_fp80 slice for a union from C where
> the padding bytes may contain real data. An x86_fp80 alloca is 16 bytes,
> and that's just fine. We can't, however, use regular loads and stores to
> access the slice, because the store size is only 10 bytes / 80 bits.
> Instead, use memcpy and memset.
>
> Fixes PR18726.
>
> http://reviews.llvm.org/D5012
>
> Files:
>   lib/Transforms/Scalar/SROA.cpp
>   test/Transforms/SROA/slice-width.ll
>
> Index: lib/Transforms/Scalar/SROA.cpp
> ===================================================================
> --- lib/Transforms/Scalar/SROA.cpp
> +++ lib/Transforms/Scalar/SROA.cpp
> @@ -2422,6 +2422,7 @@
>      if (!VecTy && !IntTy &&
>          (BeginOffset > NewAllocaBeginOffset ||
>           EndOffset < NewAllocaEndOffset ||
> +         SliceSize != DL.getTypeStoreSize(AllocaTy) ||
>           !AllocaTy->isSingleValueType() ||
>           !DL.isLegalInteger(DL.getTypeSizeInBits(ScalarTy)) ||
>           DL.getTypeSizeInBits(ScalarTy)%8 != 0)) {
> @@ -2544,10 +2545,11 @@
>
>      // If this doesn't map cleanly onto the alloca type, and that type
> isn't
>      // a single value type, just emit a memcpy.
> -    bool EmitMemCpy
> -      = !VecTy && !IntTy && (BeginOffset > NewAllocaBeginOffset ||
> -                             EndOffset < NewAllocaEndOffset ||
> -
>  !NewAI.getAllocatedType()->isSingleValueType());
> +    bool EmitMemCpy =
> +        !VecTy && !IntTy &&
> +        (BeginOffset > NewAllocaBeginOffset || EndOffset <
> NewAllocaEndOffset ||
> +         SliceSize != DL.getTypeStoreSize(NewAI.getAllocatedType()) ||
> +         !NewAI.getAllocatedType()->isSingleValueType());
>
>      // If we're just going to emit a memcpy, the alloca hasn't changed,
> and the
>      // size hasn't been shrunk based on analysis of the viable range,
> this is
> Index: test/Transforms/SROA/slice-width.ll
> ===================================================================
> --- test/Transforms/SROA/slice-width.ll
> +++ test/Transforms/SROA/slice-width.ll
> @@ -1,7 +1,8 @@
>  ; 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"
> +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-f80:128-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
> +declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, 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
> @@ -23,3 +24,57 @@
>    %t1 = load i1* %p1
>    ret void
>  }
> +
> +; PR18726: Check that we use memcpy and memset to fill out padding when
> we have
> +; a slice with a simple single type whose store size is smaller than the
> slice
> +; size.
> +
> +%union.Foo = type { x86_fp80, i64, i64 }
> +
> + at foo_copy_source = external constant %union.Foo
> + at i64_sink = global i64 0
> +
> +define void @memcpy_fp80_padding(%union.Foo* sret %res) {
> +  %x = alloca %union.Foo
> +
> +  ; Copy from a global.
> +  %x_i8 = bitcast %union.Foo* %x to i8*
> +  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x_i8, i8* bitcast
> (%union.Foo* @foo_copy_source to i8*), i32 32, i32 16, i1 false)
> +
> +  ; Access a slice of the alloca to trigger SROA.
> +  %mid_p = getelementptr %union.Foo* %x, i32 0, i32 1
> +  %elt = load i64* %mid_p
> +  store i64 %elt, i64* @i64_sink
> +
> +  ; Copy out.
> +  %res_i8 = bitcast %union.Foo* %res to i8*
> +  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %res_i8, i8* %x_i8, i32 32,
> i32 16, i1 false)
> +  ret void
> +}
> +; CHECK-LABEL: define void @memcpy_fp80_padding
> +; CHECK: alloca x86_fp80
> +; CHECK: call void @llvm.memcpy.p0i8.p0i8.i32
> +; CHECK: load i64* getelementptr inbounds (%union.Foo* @foo_copy_source,
> i64 0, i32 1)
> +; CHECK: load i64* getelementptr inbounds (%union.Foo* @foo_copy_source,
> i64 0, i32 2)
> +
> +define void @memset_fp80_padding(%union.Foo* sret %res) {
> +  %x = alloca %union.Foo
> +
> +  ; Set to all ones.
> +  %x_i8 = bitcast %union.Foo* %x to i8*
> +  call void @llvm.memset.p0i8.i32(i8* %x_i8, i8 -1, i32 32, i32 16, i1
> false)
> +
> +  ; Access a slice of the alloca to trigger SROA.
> +  %mid_p = getelementptr %union.Foo* %x, i32 0, i32 1
> +  %elt = load i64* %mid_p
> +  store i64 %elt, i64* @i64_sink
> +
> +  ; Copy out.
> +  %res_i8 = bitcast %union.Foo* %res to i8*
> +  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %res_i8, i8* %x_i8, i32 32,
> i32 16, i1 false)
> +  ret void
> +}
> +; CHECK-LABEL: define void @memset_fp80_padding
> +; CHECK: alloca x86_fp80
> +; CHECK: call void @llvm.memset.p0i8.i32(i8* %{{.*}}, i8 -1, i32 16, i32
> 16, i1 false)
> +; CHECK: store i64 -1, i64* @i64_sink
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140821/82dc83cc/attachment.html>


More information about the llvm-commits mailing list