diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -1579,8 +1579,14 @@ // Treat byval or inalloca arguments the same as Allocas, stores to them are // dead at the end of the function. for (Argument &AI : F.args()) - if (AI.hasPassPointeeByValueAttr()) - State.InvisibleToCallerBeforeRet.insert(&AI); + if (AI.hasPassPointeeByValueAttr()) { + // Pointers marked as byval cannot be accessed even if the function + // exits through an exception. + if (AI.hasByValAttr()) + State.InvisibleToCallerBeforeRet.insert(&AI); + State.InvisibleToCallerAfterRet.insert(&AI); + } + return State; } diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/simple-todo.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/simple-todo.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/simple-todo.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/simple-todo.ll @@ -10,37 +10,6 @@ declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32) nounwind declare void @llvm.init.trampoline(i8*, i8*, i8*) -; Test for byval handling. -%struct.x = type { i32, i32, i32, i32 } -define void @test9(%struct.x* byval %a) nounwind { -; CHECK-LABEL: @test9( -; CHECK-NEXT: ret void -; - %tmp2 = getelementptr %struct.x, %struct.x* %a, i32 0, i32 0 - store i32 1, i32* %tmp2, align 4 - ret void -} - -; Test for inalloca handling. -define void @test9_2(%struct.x* inalloca %a) nounwind { -; CHECK-LABEL: @test9_2( -; CHECK-NEXT: ret void -; - %tmp2 = getelementptr %struct.x, %struct.x* %a, i32 0, i32 0 - store i32 1, i32* %tmp2, align 4 - ret void -} - -; Test for preallocated handling. -define void @test9_3(%struct.x* preallocated(%struct.x) %a) nounwind { -; CHECK-LABEL: @test9_3( -; CHECK-NEXT: ret void -; - %tmp2 = getelementptr %struct.x, %struct.x* %a, i32 0, i32 0 - store i32 1, i32* %tmp2, align 4 - ret void -} - ; DSE should delete the dead trampoline. declare void @test11f() define void @test11() { @@ -57,17 +26,6 @@ declare noalias i8* @malloc(i32) declare noalias i8* @calloc(i32, i32) -define void @test22(i1 %i, i32 %k, i32 %m) nounwind { -; CHECK-LABEL: @test22( -; CHECK-NEXT: ret void -; - %k.addr = alloca i32 - %m.addr = alloca i32 - %k.addr.m.addr = select i1 %i, i32* %k.addr, i32* %m.addr - store i32 0, i32* %k.addr.m.addr, align 4 - ret void -} - declare void @unknown_func() ; Remove redundant store if loaded value is in another block inside a loop. diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/simple.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/simple.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/simple.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/simple.ll @@ -23,6 +23,7 @@ ; PR8677 @g = global i32 1 + define i32 @test3(i32* %g_addr) nounwind { ; CHECK-LABEL: @test3( ; CHECK-NEXT: [[G_VALUE:%.*]] = load i32, i32* [[G_ADDR:%.*]], align 4 @@ -136,6 +137,37 @@ } +; Test for byval handling. +%struct.x = type { i32, i32, i32, i32 } +define void @test9(%struct.x* byval %a) nounwind { +; CHECK-LABEL: @test9( +; CHECK-NEXT: ret void +; + %tmp2 = getelementptr %struct.x, %struct.x* %a, i32 0, i32 0 + store i32 1, i32* %tmp2, align 4 + ret void +} + +; Test for inalloca handling. +define void @test9_2(%struct.x* inalloca %a) nounwind { +; CHECK-LABEL: @test9_2( +; CHECK-NEXT: ret void +; + %tmp2 = getelementptr %struct.x, %struct.x* %a, i32 0, i32 0 + store i32 1, i32* %tmp2, align 4 + ret void +} + +; Test for preallocated handling. +define void @test9_3(%struct.x* preallocated(%struct.x) %a) nounwind { +; CHECK-LABEL: @test9_3( +; CHECK-NEXT: ret void +; + %tmp2 = getelementptr %struct.x, %struct.x* %a, i32 0, i32 0 + store i32 1, i32* %tmp2, align 4 + ret void +} + ; va_arg has fuzzy dependence, the store shouldn't be zapped. define double @test10(i8* %X) { ; CHECK-LABEL: @test10( @@ -223,6 +255,17 @@ ret void } +define void @test22(i1 %i, i32 %k, i32 %m) nounwind { +; CHECK-LABEL: @test22( +; CHECK-NEXT: ret void +; + %k.addr = alloca i32 + %m.addr = alloca i32 + %k.addr.m.addr = select i1 %i, i32* %k.addr, i32* %m.addr + store i32 0, i32* %k.addr.m.addr, align 4 + ret void +} + ; The store here is not dead because the byval call reads it. declare void @test19f({i32}* byval align 4 %P)