[llvm] r348645 - [MemCpyOpt] memset->memcpy forwarding with undef tail

David Jones via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 12 19:03:57 PST 2018


Here is a test case that demonstrates the incorrectly-truncated memset:

=====
%"struct.T1" = type { i32, i32, i8, i8, i8, i32, i32, double, double,
%"class.T3", %"class.T3" }
%"class.T2" = type { i8* }
%"class.T3" = type { i8* }

; Function Attrs: inlinehint nounwind uwtable
define linkonce_odr dso_local void @f(%"class.T2"* noalias sret) comdat {
  %2 = alloca %"struct.T1", align 8
  %3 = bitcast %"struct.T1"* %2 to i8*

  %4 = getelementptr inbounds %"struct.T1", %"struct.T1"* %2, i64 0, i32 5
  store i32 0, i32* %4, align 4
  %5 = getelementptr inbounds %"struct.T1", %"struct.T1"* %2, i64 0, i32 6
  store i32 0, i32* %5, align 8

  %6 = getelementptr inbounds %"struct.T1", %"struct.T1"* %2, i64 0, i32 7
  %7 = bitcast double* %6 to i8*
  call void @llvm.memset.p0i8.i64(i8* nonnull align 8 %7, i8 0, i64 64, i1
false) #3

  %8 = bitcast %"struct.T1"* %2 to i8*
  call void @llvm.memset.p0i8.i64(i8* nonnull align 8 %8, i8 0, i64 11, i1
false)

  %9 = tail call i8* @_Znwm(i64 88) #19
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 8 %9, i8* nonnull
align 8 %3, i64 40, i1 false) #3

  %10 = getelementptr inbounds i8, i8* %9, i64 40
  %11 = bitcast i8* %10 to %"class.T3"*
  %12 = getelementptr inbounds %"struct.T1", %"struct.T1"* %2, i64 0, i32 9
  call void @ext_f1(%"class.T3"* nonnull %11, %"class.T3"* nonnull
dereferenceable(24) %12) #3

  %13 = ptrtoint i8* %9 to i64
  %14 = bitcast %"class.T2"* %0 to i64*
  store i64 %13, i64* %14, align 8

  ret void
}

declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8*
nocapture readonly, i64, i1)
declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1)
declare noalias nonnull i8* @_Znwm(i64)
declare void @ext_f1(%"class.T3"*, %"class.T3"* dereferenceable(24))
unnamed_addr

$f = comdat any

@keep = dso_local unnamed_addr constant { i8* } { i8* bitcast (void
(%"class.T2"*)* @f to i8*) }, align 8
=====

Here is the problematic output:

=====
$ diff -u --label before <( $OPT_r348577 /tmp/memset-struct.ll -O2 -f |
./llvm-dis -f - ) --label after <( $OPT_r348661 /tmp/memset-struct.ll -O2
-f | ./llvm-dis -f - )
--- before
+++ after
@@ -21,7 +21,7 @@
   call void @llvm.memset.p0i8.i64(i8* nonnull align 8 %7, i8 0, i64 64, i1
false)
   call void @llvm.memset.p0i8.i64(i8* nonnull align 8 %3, i8 0, i64 11, i1
false)
   %8 = tail call i8* @_Znwm(i64 88)
-  call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 8 %8, i8* nonnull
align 8 %3, i64 40, i1 false)
+  call void @llvm.memset.p0i8.i64(i8* nonnull align 8 %8, i8 0, i64 11, i1
false)
   %9 = getelementptr inbounds i8, i8* %8, i64 40
   %10 = bitcast i8* %9 to %class.T3*
   %11 = getelementptr inbounds %struct.T1, %struct.T1* %2, i64 0, i32 9
@@ -33,9 +33,6 @@
 }

 ; Function Attrs: argmemonly nounwind
-declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8*
nocapture readonly, i64, i1) #0
-
-; Function Attrs: argmemonly nounwind
 declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1) #0

 declare noalias nonnull i8* @_Znwm(i64) local_unnamed_addr
=====

Since I haven't heard anything back since my last message, I will go ahead
and revert this patch. (Sorry about that... :-/ )

On Wed, Dec 12, 2018 at 4:21 PM David Jones <dlj at google.com> wrote:

> Hello,
>
> I'm seeing miscompiles at -O2 that bisect to this revision. I'm working on
> reducing a test case now... it looks to my (admittedly unfamiliar) eyes
> like this revision may not correctly handle structs correctly if they are
> alloca'ed.
>
> I'll update when I have more (or a test case).
>
> --dlj
>
> On Fri, Dec 7, 2018 at 1:19 PM Nikita Popov via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
>> Author: nikic
>> Date: Fri Dec  7 13:16:58 2018
>> New Revision: 348645
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=348645&view=rev
>> Log:
>> [MemCpyOpt] memset->memcpy forwarding with undef tail
>>
>> Currently memcpyopt optimizes cases like
>>
>>     memset(a, byte, N);
>>     memcpy(b, a, M);
>>
>> to
>>
>>     memset(a, byte, N);
>>     memset(b, byte, M);
>>
>> if M <= N. Often this allows further simplifications down the line,
>> which drop the first memset entirely.
>>
>> This patch extends this optimization for the case where M > N, but we
>> know that the bytes a[N..M] are undef due to alloca/lifetime.start.
>>
>> This situation arises relatively often for Rust code, because Rust does
>> not initialize trailing structure padding and loves to insert redundant
>> memcpys. This also fixes https://bugs.llvm.org/show_bug.cgi?id=39844.
>>
>> For the implementation, I'm reusing a bit of code for a similar existing
>> optimization (direct memcpy of undef). I've also added memset support to
>> MemDepAnalysis GetLocation -- Instead, getPointerDependencyFrom could be
>> used, but it seems to make more sense to add this to GetLocation and thus
>> make the computation cachable.
>>
>> Differential Revision: https://reviews.llvm.org/D55120
>>
>> Modified:
>>     llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp
>>     llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp
>>     llvm/trunk/test/Transforms/MemCpyOpt/memset-memcpy-oversized.ll
>>
>> Modified: llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp?rev=348645&r1=348644&r2=348645&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp (original)
>> +++ llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp Fri Dec  7
>> 13:16:58 2018
>> @@ -154,6 +154,12 @@ static ModRefInfo GetLocation(const Inst
>>      return ModRefInfo::Mod;
>>    }
>>
>> +  if (const MemSetInst *MI = dyn_cast<MemSetInst>(Inst)) {
>> +    Loc = MemoryLocation::getForDest(MI);
>> +    // Conversatively assume ModRef for volatile memset.
>> +    return MI->isVolatile() ? ModRefInfo::ModRef : ModRefInfo::Mod;
>> +  }
>> +
>>    if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst)) {
>>      switch (II->getIntrinsicID()) {
>>      case Intrinsic::lifetime_start:
>>
>> Modified: llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp?rev=348645&r1=348644&r2=348645&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp (original)
>> +++ llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp Fri Dec  7
>> 13:16:58 2018
>> @@ -1144,6 +1144,21 @@ bool MemCpyOptPass::processMemSetMemCpyD
>>    return true;
>>  }
>>
>> +/// Determine whether the instruction has undefined content for the
>> given Size,
>> +/// either because it was freshly alloca'd or started its lifetime.
>> +static bool hasUndefContents(Instruction *I, ConstantInt *Size) {
>> +  if (isa<AllocaInst>(I))
>> +    return true;
>> +
>> +  if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
>> +    if (II->getIntrinsicID() == Intrinsic::lifetime_start)
>> +      if (ConstantInt *LTSize =
>> dyn_cast<ConstantInt>(II->getArgOperand(0)))
>> +        if (LTSize->getZExtValue() >= Size->getZExtValue())
>> +          return true;
>> +
>> +  return false;
>> +}
>> +
>>  /// Transform memcpy to memset when its source was just memset.
>>  /// In other words, turn:
>>  /// \code
>> @@ -1167,12 +1182,23 @@ bool MemCpyOptPass::performMemCpyToMemSe
>>    if (!AA.isMustAlias(MemSet->getRawDest(), MemCpy->getRawSource()))
>>      return false;
>>
>> -  ConstantInt *CopySize = cast<ConstantInt>(MemCpy->getLength());
>> +  // A known memset size is required.
>>    ConstantInt *MemSetSize = dyn_cast<ConstantInt>(MemSet->getLength());
>> +  if (!MemSetSize)
>> +    return false;
>> +
>>    // Make sure the memcpy doesn't read any more than what the memset
>> wrote.
>>    // Don't worry about sizes larger than i64.
>> -  if (!MemSetSize || CopySize->getZExtValue() >
>> MemSetSize->getZExtValue())
>> -    return false;
>> +  ConstantInt *CopySize = cast<ConstantInt>(MemCpy->getLength());
>> +  if (CopySize->getZExtValue() > MemSetSize->getZExtValue()) {
>> +    // If the memcpy is larger than the memset, but the memory was undef
>> prior
>> +    // to the memset, we can just ignore the tail.
>> +    MemDepResult DepInfo = MD->getDependency(MemSet);
>> +    if (DepInfo.isDef() && hasUndefContents(DepInfo.getInst(), CopySize))
>> +      CopySize = MemSetSize;
>> +    else
>> +      return false;
>> +  }
>>
>>    IRBuilder<> Builder(MemCpy);
>>    Builder.CreateMemSet(MemCpy->getRawDest(), MemSet->getOperand(1),
>> @@ -1252,19 +1278,7 @@ bool MemCpyOptPass::processMemCpy(MemCpy
>>      if (MemCpyInst *MDep = dyn_cast<MemCpyInst>(SrcDepInfo.getInst()))
>>        return processMemCpyMemCpyDependence(M, MDep);
>>    } else if (SrcDepInfo.isDef()) {
>> -    Instruction *I = SrcDepInfo.getInst();
>> -    bool hasUndefContents = false;
>> -
>> -    if (isa<AllocaInst>(I)) {
>> -      hasUndefContents = true;
>> -    } else if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
>> -      if (II->getIntrinsicID() == Intrinsic::lifetime_start)
>> -        if (ConstantInt *LTSize =
>> dyn_cast<ConstantInt>(II->getArgOperand(0)))
>> -          if (LTSize->getZExtValue() >= CopySize->getZExtValue())
>> -            hasUndefContents = true;
>> -    }
>> -
>> -    if (hasUndefContents) {
>> +    if (hasUndefContents(SrcDepInfo.getInst(), CopySize)) {
>>        MD->removeInstruction(M);
>>        M->eraseFromParent();
>>        ++NumMemCpyInstr;
>>
>> Modified: llvm/trunk/test/Transforms/MemCpyOpt/memset-memcpy-oversized.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/MemCpyOpt/memset-memcpy-oversized.ll?rev=348645&r1=348644&r2=348645&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/test/Transforms/MemCpyOpt/memset-memcpy-oversized.ll
>> (original)
>> +++ llvm/trunk/test/Transforms/MemCpyOpt/memset-memcpy-oversized.ll Fri
>> Dec  7 13:16:58 2018
>> @@ -12,7 +12,7 @@ define void @test_alloca(i8* %result) {
>>  ; CHECK-NEXT:    [[A:%.*]] = alloca [[T:%.*]], align 8
>>  ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
>>  ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8
>> 0, i64 12, i1 false)
>> -; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8*
>> [[RESULT:%.*]], i8* align 8 [[B]], i64 16, i1 false)
>> +; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[RESULT:%.*]], i8
>> 0, i64 12, i1 false)
>>  ; CHECK-NEXT:    ret void
>>  ;
>>    %a = alloca %T, align 8
>> @@ -28,7 +28,7 @@ define void @test_alloca_with_lifetimes(
>>  ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
>>  ; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 16, i8* [[B]])
>>  ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8
>> 0, i64 12, i1 false)
>> -; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8*
>> [[RESULT:%.*]], i8* align 8 [[B]], i64 16, i1 false)
>> +; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[RESULT:%.*]], i8
>> 0, i64 12, i1 false)
>>  ; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 16, i8* [[B]])
>>  ; CHECK-NEXT:    ret void
>>  ;
>> @@ -46,7 +46,7 @@ define void @test_malloc_with_lifetimes(
>>  ; CHECK-NEXT:    [[A:%.*]] = call i8* @malloc(i64 16)
>>  ; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 16, i8* [[A]])
>>  ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[A]], i8
>> 0, i64 12, i1 false)
>> -; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8*
>> [[RESULT:%.*]], i8* align 8 [[A]], i64 16, i1 false)
>> +; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[RESULT:%.*]], i8
>> 0, i64 12, i1 false)
>>  ; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 16, i8* [[A]])
>>  ; CHECK-NEXT:    call void @free(i8* [[A]])
>>  ; CHECK-NEXT:    ret void
>> @@ -98,7 +98,7 @@ define void @test_volatile_memset(i8* %r
>>  ; CHECK-NEXT:    [[A:%.*]] = alloca [[T:%.*]], align 8
>>  ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
>>  ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8
>> 0, i64 12, i1 true)
>> -; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8*
>> [[RESULT:%.*]], i8* align 8 [[B]], i64 16, i1 false)
>> +; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[RESULT:%.*]], i8
>> 0, i64 12, i1 false)
>>  ; CHECK-NEXT:    ret void
>>  ;
>>    %a = alloca %T, align 8
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>
>
On Wed, Dec 12, 2018 at 4:21 PM David Jones <dlj at google.com> wrote:

> Hello,
>
> I'm seeing miscompiles at -O2 that bisect to this revision. I'm working on
> reducing a test case now... it looks to my (admittedly unfamiliar) eyes
> like this revision may not correctly handle structs correctly if they are
> alloca'ed.
>
> I'll update when I have more (or a test case).
>
> --dlj
>
> On Fri, Dec 7, 2018 at 1:19 PM Nikita Popov via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
>> Author: nikic
>> Date: Fri Dec  7 13:16:58 2018
>> New Revision: 348645
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=348645&view=rev
>> Log:
>> [MemCpyOpt] memset->memcpy forwarding with undef tail
>>
>> Currently memcpyopt optimizes cases like
>>
>>     memset(a, byte, N);
>>     memcpy(b, a, M);
>>
>> to
>>
>>     memset(a, byte, N);
>>     memset(b, byte, M);
>>
>> if M <= N. Often this allows further simplifications down the line,
>> which drop the first memset entirely.
>>
>> This patch extends this optimization for the case where M > N, but we
>> know that the bytes a[N..M] are undef due to alloca/lifetime.start.
>>
>> This situation arises relatively often for Rust code, because Rust does
>> not initialize trailing structure padding and loves to insert redundant
>> memcpys. This also fixes https://bugs.llvm.org/show_bug.cgi?id=39844.
>>
>> For the implementation, I'm reusing a bit of code for a similar existing
>> optimization (direct memcpy of undef). I've also added memset support to
>> MemDepAnalysis GetLocation -- Instead, getPointerDependencyFrom could be
>> used, but it seems to make more sense to add this to GetLocation and thus
>> make the computation cachable.
>>
>> Differential Revision: https://reviews.llvm.org/D55120
>>
>> Modified:
>>     llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp
>>     llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp
>>     llvm/trunk/test/Transforms/MemCpyOpt/memset-memcpy-oversized.ll
>>
>> Modified: llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp?rev=348645&r1=348644&r2=348645&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp (original)
>> +++ llvm/trunk/lib/Analysis/MemoryDependenceAnalysis.cpp Fri Dec  7
>> 13:16:58 2018
>> @@ -154,6 +154,12 @@ static ModRefInfo GetLocation(const Inst
>>      return ModRefInfo::Mod;
>>    }
>>
>> +  if (const MemSetInst *MI = dyn_cast<MemSetInst>(Inst)) {
>> +    Loc = MemoryLocation::getForDest(MI);
>> +    // Conversatively assume ModRef for volatile memset.
>> +    return MI->isVolatile() ? ModRefInfo::ModRef : ModRefInfo::Mod;
>> +  }
>> +
>>    if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst)) {
>>      switch (II->getIntrinsicID()) {
>>      case Intrinsic::lifetime_start:
>>
>> Modified: llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp?rev=348645&r1=348644&r2=348645&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp (original)
>> +++ llvm/trunk/lib/Transforms/Scalar/MemCpyOptimizer.cpp Fri Dec  7
>> 13:16:58 2018
>> @@ -1144,6 +1144,21 @@ bool MemCpyOptPass::processMemSetMemCpyD
>>    return true;
>>  }
>>
>> +/// Determine whether the instruction has undefined content for the
>> given Size,
>> +/// either because it was freshly alloca'd or started its lifetime.
>> +static bool hasUndefContents(Instruction *I, ConstantInt *Size) {
>> +  if (isa<AllocaInst>(I))
>> +    return true;
>> +
>> +  if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
>> +    if (II->getIntrinsicID() == Intrinsic::lifetime_start)
>> +      if (ConstantInt *LTSize =
>> dyn_cast<ConstantInt>(II->getArgOperand(0)))
>> +        if (LTSize->getZExtValue() >= Size->getZExtValue())
>> +          return true;
>> +
>> +  return false;
>> +}
>> +
>>  /// Transform memcpy to memset when its source was just memset.
>>  /// In other words, turn:
>>  /// \code
>> @@ -1167,12 +1182,23 @@ bool MemCpyOptPass::performMemCpyToMemSe
>>    if (!AA.isMustAlias(MemSet->getRawDest(), MemCpy->getRawSource()))
>>      return false;
>>
>> -  ConstantInt *CopySize = cast<ConstantInt>(MemCpy->getLength());
>> +  // A known memset size is required.
>>    ConstantInt *MemSetSize = dyn_cast<ConstantInt>(MemSet->getLength());
>> +  if (!MemSetSize)
>> +    return false;
>> +
>>    // Make sure the memcpy doesn't read any more than what the memset
>> wrote.
>>    // Don't worry about sizes larger than i64.
>> -  if (!MemSetSize || CopySize->getZExtValue() >
>> MemSetSize->getZExtValue())
>> -    return false;
>> +  ConstantInt *CopySize = cast<ConstantInt>(MemCpy->getLength());
>> +  if (CopySize->getZExtValue() > MemSetSize->getZExtValue()) {
>> +    // If the memcpy is larger than the memset, but the memory was undef
>> prior
>> +    // to the memset, we can just ignore the tail.
>> +    MemDepResult DepInfo = MD->getDependency(MemSet);
>> +    if (DepInfo.isDef() && hasUndefContents(DepInfo.getInst(), CopySize))
>> +      CopySize = MemSetSize;
>> +    else
>> +      return false;
>> +  }
>>
>>    IRBuilder<> Builder(MemCpy);
>>    Builder.CreateMemSet(MemCpy->getRawDest(), MemSet->getOperand(1),
>> @@ -1252,19 +1278,7 @@ bool MemCpyOptPass::processMemCpy(MemCpy
>>      if (MemCpyInst *MDep = dyn_cast<MemCpyInst>(SrcDepInfo.getInst()))
>>        return processMemCpyMemCpyDependence(M, MDep);
>>    } else if (SrcDepInfo.isDef()) {
>> -    Instruction *I = SrcDepInfo.getInst();
>> -    bool hasUndefContents = false;
>> -
>> -    if (isa<AllocaInst>(I)) {
>> -      hasUndefContents = true;
>> -    } else if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
>> -      if (II->getIntrinsicID() == Intrinsic::lifetime_start)
>> -        if (ConstantInt *LTSize =
>> dyn_cast<ConstantInt>(II->getArgOperand(0)))
>> -          if (LTSize->getZExtValue() >= CopySize->getZExtValue())
>> -            hasUndefContents = true;
>> -    }
>> -
>> -    if (hasUndefContents) {
>> +    if (hasUndefContents(SrcDepInfo.getInst(), CopySize)) {
>>        MD->removeInstruction(M);
>>        M->eraseFromParent();
>>        ++NumMemCpyInstr;
>>
>> Modified: llvm/trunk/test/Transforms/MemCpyOpt/memset-memcpy-oversized.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/MemCpyOpt/memset-memcpy-oversized.ll?rev=348645&r1=348644&r2=348645&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/test/Transforms/MemCpyOpt/memset-memcpy-oversized.ll
>> (original)
>> +++ llvm/trunk/test/Transforms/MemCpyOpt/memset-memcpy-oversized.ll Fri
>> Dec  7 13:16:58 2018
>> @@ -12,7 +12,7 @@ define void @test_alloca(i8* %result) {
>>  ; CHECK-NEXT:    [[A:%.*]] = alloca [[T:%.*]], align 8
>>  ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
>>  ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8
>> 0, i64 12, i1 false)
>> -; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8*
>> [[RESULT:%.*]], i8* align 8 [[B]], i64 16, i1 false)
>> +; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[RESULT:%.*]], i8
>> 0, i64 12, i1 false)
>>  ; CHECK-NEXT:    ret void
>>  ;
>>    %a = alloca %T, align 8
>> @@ -28,7 +28,7 @@ define void @test_alloca_with_lifetimes(
>>  ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
>>  ; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 16, i8* [[B]])
>>  ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8
>> 0, i64 12, i1 false)
>> -; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8*
>> [[RESULT:%.*]], i8* align 8 [[B]], i64 16, i1 false)
>> +; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[RESULT:%.*]], i8
>> 0, i64 12, i1 false)
>>  ; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 16, i8* [[B]])
>>  ; CHECK-NEXT:    ret void
>>  ;
>> @@ -46,7 +46,7 @@ define void @test_malloc_with_lifetimes(
>>  ; CHECK-NEXT:    [[A:%.*]] = call i8* @malloc(i64 16)
>>  ; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 16, i8* [[A]])
>>  ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[A]], i8
>> 0, i64 12, i1 false)
>> -; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8*
>> [[RESULT:%.*]], i8* align 8 [[A]], i64 16, i1 false)
>> +; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[RESULT:%.*]], i8
>> 0, i64 12, i1 false)
>>  ; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 16, i8* [[A]])
>>  ; CHECK-NEXT:    call void @free(i8* [[A]])
>>  ; CHECK-NEXT:    ret void
>> @@ -98,7 +98,7 @@ define void @test_volatile_memset(i8* %r
>>  ; CHECK-NEXT:    [[A:%.*]] = alloca [[T:%.*]], align 8
>>  ; CHECK-NEXT:    [[B:%.*]] = bitcast %T* [[A]] to i8*
>>  ; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* align 8 [[B]], i8
>> 0, i64 12, i1 true)
>> -; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8*
>> [[RESULT:%.*]], i8* align 8 [[B]], i64 16, i1 false)
>> +; CHECK-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[RESULT:%.*]], i8
>> 0, i64 12, i1 false)
>>  ; CHECK-NEXT:    ret void
>>  ;
>>    %a = alloca %T, align 8
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20181212/9746f1ea/attachment.html>


More information about the llvm-commits mailing list