diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp --- a/llvm/lib/Transforms/Scalar/GVN.cpp +++ b/llvm/lib/Transforms/Scalar/GVN.cpp @@ -999,6 +999,20 @@ Res = CoercedLoad; } else { Res = getValueForLoad(CoercedLoad, Offset, LoadTy, InsertPt, DL); + // We are adding a new user for this load, for which the original + // metadata may not hold. Additionally, the new load may have a different + // size and type, so their metadata cannot be combined in any + // straightforward way. + // Drop all metadata that is not known to cause immediate UB on violation, + // unless the load has !noundef, in which case all metadata violations + // will be promoted to UB. + // TODO: We can combine noalias/alias.scope metadata here, because it is + // independent of the load type. + if (!CoercedLoad->hasMetadata(LLVMContext::MD_noundef)) + CoercedLoad->dropUnknownNonDebugMetadata( + {LLVMContext::MD_dereferenceable, + LLVMContext::MD_dereferenceable_or_null, + LLVMContext::MD_invariant_load, LLVMContext::MD_invariant_group}); LLVM_DEBUG(dbgs() << "GVN COERCED NONLOCAL LOAD:\nOffset: " << Offset << " " << *getCoercedLoadValue() << '\n' << *Res << '\n' diff --git a/llvm/test/Transforms/GVN/metadata.ll b/llvm/test/Transforms/GVN/metadata.ll --- a/llvm/test/Transforms/GVN/metadata.ll +++ b/llvm/test/Transforms/GVN/metadata.ll @@ -168,7 +168,7 @@ define void @load_ptr_nonnull_to_i64(ptr %p) { ; CHECK-LABEL: define void @load_ptr_nonnull_to_i64 ; CHECK-SAME: (ptr [[P:%.*]]) { -; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[P]], align 8, !nonnull !6 +; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[P]], align 8 ; CHECK-NEXT: [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64 ; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) ; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) @@ -253,7 +253,7 @@ define void @load_ptr_nonnull_to_i32(ptr %p) { ; CHECK-LABEL: define void @load_ptr_nonnull_to_i32 ; CHECK-SAME: (ptr [[P:%.*]]) { -; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[P]], align 8, !nonnull !6 +; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[P]], align 8 ; CHECK-NEXT: [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64 ; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[VAL_INT]] to i32 ; CHECK-NEXT: call void @use.i64(i64 [[VAL_INT]]) @@ -271,7 +271,7 @@ define void @load_i64_range_to_i32_range(ptr %p) { ; CHECK-LABEL: define void @load_i64_range_to_i32_range ; CHECK-SAME: (ptr [[P:%.*]]) { -; CHECK-NEXT: [[VAL:%.*]] = load i64, ptr [[P]], align 8, !range [[RNG8:![0-9]+]] +; CHECK-NEXT: [[VAL:%.*]] = load i64, ptr [[P]], align 8 ; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[VAL]] to i32 ; CHECK-NEXT: call void @use.i64(i64 [[VAL]]) ; CHECK-NEXT: call void @use.i32(i32 [[TMP1]]) @@ -305,5 +305,4 @@ ; CHECK: [[RNG5]] = !{i32 3, i32 4, i32 5, i32 2} ; CHECK: [[META6:![0-9]+]] = !{} ; CHECK: [[META7:![0-9]+]] = !{i64 10} -; CHECK: [[RNG8]] = !{i64 0, i64 10} ;.