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 @@ -1022,7 +1022,7 @@ return I.first->second; } - Optional getLocForWriteEx(Instruction *I) const { + Optional getLocForWriteEx(Instruction *I) { if (!I->mayWriteToMemory()) return None; @@ -1032,6 +1032,19 @@ !CB->onlyAccessesInaccessibleMemOrArgMem()) return None; + LibFunc F; + if (TLI.getLibFunc(*CB, F) && TLI.has(F) && F == LibFunc_memset_chk) { + // For the uses in DSE, it is safe to use the precise location instead + // of an upper bound. DSE uses the location information to remove + // earlier or later stores with the assumption that the memset_chk + // executes. So it either writes exactly the number of specified bytes + // or the program gets aborted. + if (const auto *Len = dyn_cast(CB->getArgOperand(2))) { + Value *Ptr = CB->getArgOperand(0); + return MemoryLocation(Ptr, LocationSize::precise(Len->getZExtValue()), + CB->getAAMetadata()); + } + } return MemoryLocation::getForDest(CB, TLI); } diff --git a/llvm/test/Transforms/DeadStoreElimination/libcalls.ll b/llvm/test/Transforms/DeadStoreElimination/libcalls.ll --- a/llvm/test/Transforms/DeadStoreElimination/libcalls.ll +++ b/llvm/test/Transforms/DeadStoreElimination/libcalls.ll @@ -468,8 +468,7 @@ ; strncpy -> __memset_chk, full overwrite define void @dse_strncpy_memset_chk_test1(i8* noalias %out, i8* noalias %in, i64 %n) { ; CHECK-LABEL: @dse_strncpy_memset_chk_test1( -; CHECK-NEXT: [[CALL:%.*]] = tail call i8* @strncpy(i8* [[OUT:%.*]], i8* [[IN:%.*]], i64 100) -; CHECK-NEXT: [[CALL_2:%.*]] = tail call i8* @__memset_chk(i8* [[OUT]], i32 42, i64 100, i64 [[N:%.*]]) +; CHECK-NEXT: [[CALL_2:%.*]] = tail call i8* @__memset_chk(i8* [[OUT:%.*]], i32 42, i64 100, i64 [[N:%.*]]) ; CHECK-NEXT: ret void ; %call = tail call i8* @strncpy(i8* %out, i8* %in, i64 100) @@ -481,8 +480,7 @@ define void @dse_memset_chk_cannot_eliminates_store(i8* %out, i64 %n) { ; CHECK-LABEL: @dse_memset_chk_cannot_eliminates_store( -; CHECK-NEXT: store i8 10, i8* [[OUT:%.*]], align 1 -; CHECK-NEXT: [[CALL_2:%.*]] = tail call i8* @__memset_chk(i8* [[OUT]], i32 42, i64 100, i64 [[N:%.*]]) +; CHECK-NEXT: [[CALL_2:%.*]] = tail call i8* @__memset_chk(i8* [[OUT:%.*]], i32 42, i64 100, i64 [[N:%.*]]) ; CHECK-NEXT: ret void ; store i8 10, i8* %out @@ -494,7 +492,6 @@ ; CHECK-LABEL: @dse_memset_chk_eliminates_store_local_object_escapes_after( ; CHECK-NEXT: [[A:%.*]] = alloca [200 x i8], align 1 ; CHECK-NEXT: [[OUT:%.*]] = bitcast [200 x i8]* [[A]] to i8* -; CHECK-NEXT: store i8 10, i8* [[OUT]], align 1 ; CHECK-NEXT: [[OUT_100:%.*]] = getelementptr i8, i8* [[OUT]], i64 100 ; CHECK-NEXT: store i8 10, i8* [[OUT_100]], align 1 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call i8* @__memset_chk(i8* [[OUT]], i32 42, i64 100, i64 [[N:%.*]]) @@ -516,7 +513,6 @@ ; CHECK-NEXT: [[A:%.*]] = alloca [200 x i8], align 1 ; CHECK-NEXT: [[OUT:%.*]] = bitcast [200 x i8]* [[A]] to i8* ; CHECK-NEXT: call void @use(i8* [[OUT]]) -; CHECK-NEXT: store i8 10, i8* [[OUT]], align 1 ; CHECK-NEXT: [[OUT_100:%.*]] = getelementptr i8, i8* [[OUT]], i64 100 ; CHECK-NEXT: store i8 0, i8* [[OUT_100]], align 1 ; CHECK-NEXT: [[CALL_2:%.*]] = tail call i8* @__memset_chk(i8* [[OUT]], i32 42, i64 100, i64 [[N:%.*]])