From d748689c7f718f531871bb44b5da05888c3c0301 Mon Sep 17 00:00:00 2001 From: Philip Reames Date: Mon, 22 Apr 2019 20:28:19 +0000 Subject: [PATCH] [InstCombine] Eliminate stores to constant memory If we have a store to a piece of memory which is known constant, then we know the store must be storing back the same value. As a result, the store (or memset, or memmove) must either be down a dead path, or a noop. In either case, it is valid to simply remove the store. The motivating case for this involves a memmove to a buffer which is constant down a path which is dynamically dead. Note that I'm choosing to implement the less aggressive of two possible semantics here. We could simply say that the store *is undefined*, and prune the path. Consensus in the review was that the more aggressive form might be a good follow on change at a later date. Differential Revision: https://reviews.llvm.org/D60659 llvm-svn: 358919 --- llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 18 ++++++++++++++++++ .../InstCombine/InstCombineLoadStoreAlloca.cpp | 6 ++++++ llvm/test/Transforms/InstCombine/memcpy.ll | 1 - llvm/test/Transforms/InstCombine/memmove.ll | 1 - llvm/test/Transforms/InstCombine/memset.ll | 1 - llvm/test/Transforms/InstCombine/store.ll | 1 - 6 files changed, 24 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 6f83284..0fe52b1 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -120,6 +120,15 @@ Instruction *InstCombiner::SimplifyAnyMemTransfer(AnyMemTransferInst *MI) { return MI; } + // If we have a store to a location which is known constant, we can conclude + // that the store must be storing the constant value (else the memory + // wouldn't be constant), and this must be a noop. + if (AA->pointsToConstantMemory(MI->getDest())) { + // Set the size of the copy to 0, it will be deleted on the next iteration. + MI->setLength(Constant::getNullValue(MI->getLength()->getType())); + return MI; + } + // If MemCpyInst length is 1/2/4/8 bytes then replace memcpy with // load/store. ConstantInt *MemOpLength = dyn_cast(MI->getLength()); @@ -218,6 +227,15 @@ Instruction *InstCombiner::SimplifyAnyMemSet(AnyMemSetInst *MI) { return MI; } + // If we have a store to a location which is known constant, we can conclude + // that the store must be storing the constant value (else the memory + // wouldn't be constant), and this must be a noop. + if (AA->pointsToConstantMemory(MI->getDest())) { + // Set the size of the copy to 0, it will be deleted on the next iteration. + MI->setLength(Constant::getNullValue(MI->getLength()->getType())); + return MI; + } + // Extract the length and alignment and fill if they are constant. ConstantInt *LenC = dyn_cast(MI->getLength()); ConstantInt *FillC = dyn_cast(MI->getValue()); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp index 38ce771..dd07561 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -1438,6 +1438,12 @@ Instruction *InstCombiner::visitStoreInst(StoreInst &SI) { } } + // If we have a store to a location which is known constant, we can conclude + // that the store must be storing the constant value (else the memory + // wouldn't be constant), and this must be a noop. + if (AA->pointsToConstantMemory(Ptr)) + return eraseInstFromFunction(SI); + // Do really simple DSE, to catch cases where there are several consecutive // stores to the same location, separated by a few arithmetic operations. This // situation often occurs with bitfield accesses. diff --git a/llvm/test/Transforms/InstCombine/memcpy.ll b/llvm/test/Transforms/InstCombine/memcpy.ll index 1adb815..ae8f96c 100644 --- a/llvm/test/Transforms/InstCombine/memcpy.ll +++ b/llvm/test/Transforms/InstCombine/memcpy.ll @@ -40,7 +40,6 @@ define void @test3(i8* %d, i8* %s) { define void @memcpy_to_constant(i8* %src) { ; CHECK-LABEL: @memcpy_to_constant( -; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 bitcast (i128* @UnknownConstant to i8*), i8* align 1 [[SRC:%.*]], i32 16, i1 false) ; CHECK-NEXT: ret void ; %dest = bitcast i128* @UnknownConstant to i8* diff --git a/llvm/test/Transforms/InstCombine/memmove.ll b/llvm/test/Transforms/InstCombine/memmove.ll index 5c69595..c5ad787 100644 --- a/llvm/test/Transforms/InstCombine/memmove.ll +++ b/llvm/test/Transforms/InstCombine/memmove.ll @@ -59,7 +59,6 @@ define void @test4(i8* %a) { define void @memmove_to_constant(i8* %src) { ; CHECK-LABEL: @memmove_to_constant( -; CHECK-NEXT: call void @llvm.memmove.p0i8.p0i8.i32(i8* align 4 bitcast (i128* @UnknownConstant to i8*), i8* align 1 [[SRC:%.*]], i32 16, i1 false) ; CHECK-NEXT: ret void ; %dest = bitcast i128* @UnknownConstant to i8* diff --git a/llvm/test/Transforms/InstCombine/memset.ll b/llvm/test/Transforms/InstCombine/memset.ll index 1efb2e4..7d531f2 100644 --- a/llvm/test/Transforms/InstCombine/memset.ll +++ b/llvm/test/Transforms/InstCombine/memset.ll @@ -26,7 +26,6 @@ define i32 @test([1024 x i8]* %target) { define void @memset_to_constant() { ; CHECK-LABEL: @memset_to_constant( -; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* align 4 bitcast (i128* @Unknown to i8*), i8 0, i32 16, i1 false) ; CHECK-NEXT: ret void ; %p = bitcast i128* @Unknown to i8* diff --git a/llvm/test/Transforms/InstCombine/store.ll b/llvm/test/Transforms/InstCombine/store.ll index c7c8374..af36289 100644 --- a/llvm/test/Transforms/InstCombine/store.ll +++ b/llvm/test/Transforms/InstCombine/store.ll @@ -295,7 +295,6 @@ define void @write_back7(i32* %p) { define void @store_to_constant() { ; CHECK-LABEL: @store_to_constant( -; CHECK-NEXT: store i32 0, i32* @Unknown, align 4 ; CHECK-NEXT: ret void ; store i32 0, i32* @Unknown -- 2.7.4