diff --git a/llvm/include/llvm/Support/TypeSize.h b/llvm/include/llvm/Support/TypeSize.h --- a/llvm/include/llvm/Support/TypeSize.h +++ b/llvm/include/llvm/Support/TypeSize.h @@ -146,6 +146,9 @@ return (MinSize & 7) == 0; } + // Returns true if the type size is non-zero. + bool isNonZero() const { return MinSize != 0; } + // Casts to a uint64_t if this is a fixed-width size. // // This interface is deprecated and will be removed in a future version diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -3561,8 +3561,8 @@ if (isa(V)) return UndefInt8; - const uint64_t Size = DL.getTypeStoreSize(V->getType()); - if (!Size) + // Return Undef for zero-sized type. + if (!DL.getTypeStoreSize(V->getType()).isNonZero()) return UndefInt8; Constant *C = dyn_cast(V); @@ -3880,7 +3880,7 @@ Array = nullptr; } else { const DataLayout &DL = GV->getParent()->getDataLayout(); - uint64_t SizeInBytes = DL.getTypeStoreSize(GVTy); + uint64_t SizeInBytes = DL.getTypeStoreSize(GVTy).getFixedSize(); uint64_t Length = SizeInBytes / (ElementSize / 8); if (Length <= Offset) return false; diff --git a/llvm/test/Transforms/MemCpyOpt/store-to-memset-is-nonzero-type.ll b/llvm/test/Transforms/MemCpyOpt/store-to-memset-is-nonzero-type.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/MemCpyOpt/store-to-memset-is-nonzero-type.ll @@ -0,0 +1,73 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S < %s -memcpyopt | FileCheck %s + +; Array + +define void @array_zero([0 x i8]* %p) { +; CHECK-LABEL: @array_zero( +; CHECK-NEXT: [[TMP1:%.*]] = bitcast [0 x i8]* [[P:%.*]] to i8* +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 1 [[TMP1]], i8 undef, i64 0, i1 false) +; CHECK-NEXT: ret void +; + store [0 x i8] zeroinitializer, [0 x i8]* %p + ret void +} + +define void @array_nonzero([1 x i8]* %p) { +; CHECK-LABEL: @array_nonzero( +; CHECK-NEXT: [[TMP1:%.*]] = bitcast [1 x i8]* [[P:%.*]] to i8* +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 1 [[TMP1]], i8 0, i64 1, i1 false) +; CHECK-NEXT: ret void +; + store [1 x i8] zeroinitializer, [1 x i8]* %p + ret void +} + +; Structure + +define void @struct_zero({ }* %p) { +; CHECK-LABEL: @struct_zero( +; CHECK-NEXT: [[TMP1:%.*]] = bitcast {}* [[P:%.*]] to i8* +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 1 [[TMP1]], i8 undef, i64 0, i1 false) +; CHECK-NEXT: ret void +; + store { } zeroinitializer, { }* %p + ret void +} +define void @struct_nonzero({ i8 }* %p) { +; CHECK-LABEL: @struct_nonzero( +; CHECK-NEXT: [[TMP1:%.*]] = bitcast { i8 }* [[P:%.*]] to i8* +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 1 [[TMP1]], i8 0, i64 1, i1 false) +; CHECK-NEXT: ret void +; + store { i8 } zeroinitializer, { i8 }* %p + ret void +} + +; Vector + +; Test only non-zero vector. Zero element vector is illegal + +define void @vector_fixed_length_nonzero(<16 x i8>* %p) { +; CHECK-LABEL: @vector_fixed_length_nonzero( +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr <16 x i8>, <16 x i8>* [[P:%.*]], i64 0 +; CHECK-NEXT: [[TMP1:%.*]] = getelementptr <16 x i8>, <16 x i8>* [[P]], i64 1 +; CHECK-NEXT: [[TMP1:%.*]] = bitcast <16 x i8>* [[TMP0]] to i8* +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 16 [[TMP1]], i8 0, i64 32, i1 false) +; CHECK-NEXT: ret void +; + %tmp0 = getelementptr <16 x i8>, <16 x i8>* %p, i64 0 + store <16 x i8> zeroinitializer, <16 x i8>* %tmp0 + %tmp1 = getelementptr <16 x i8>, <16 x i8>* %p, i64 1 + store <16 x i8> zeroinitializer, <16 x i8>* %tmp1 + ret void +} + +define void @vector_scalable_nonzero(* %p) { +; CHECK-LABEL: @vector_scalable_nonzero( +; CHECK-NEXT: store zeroinitializer, * [[P:%.*]] +; CHECK-NEXT: ret void +; + store zeroinitializer, * %p + ret void +}