diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -1175,10 +1175,18 @@ unsigned StoreSize = DL.getTypeStoreSize(Shadow->getType()); Value *ConvertedShadow = convertShadowToScalar(Shadow, IRB); if (auto *ConstantShadow = dyn_cast(ConvertedShadow)) { - if (ClCheckConstantShadow && !ConstantShadow->isZeroValue()) + if (!ClCheckConstantShadow || ConstantShadow->isZeroValue()) { + // Origin is not needed: value is initialized or const shadow is + // ignored. + return; + } + if (llvm::isKnownNonZero(ConvertedShadow, DL)) { + // Copy origin as the value is definitely uninitialized. paintOrigin(IRB, updateOrigin(Origin, IRB), OriginPtr, StoreSize, OriginAlignment); - return; + return; + } + // Fallback to runtime check, which still can be optimized out later. } unsigned TypeSizeInBits = DL.getTypeSizeInBits(ConvertedShadow->getType()); @@ -1246,15 +1254,20 @@ Value *ConvertedShadow = convertShadowToScalar(Shadow, IRB); LLVM_DEBUG(dbgs() << " SHAD1 : " << *ConvertedShadow << "\n"); + const DataLayout &DL = OrigIns->getModule()->getDataLayout(); if (auto *ConstantShadow = dyn_cast(ConvertedShadow)) { - if (ClCheckConstantShadow && !ConstantShadow->isZeroValue()) { + if (!ClCheckConstantShadow || ConstantShadow->isZeroValue()) { + // Value is initialized or const shadow is ignored. + return; + } + if (llvm::isKnownNonZero(ConvertedShadow, DL)) { + // Report as the value is definitely uninitialized. insertWarningFn(IRB, Origin); + return; } - return; + // Fallback to runtime check, which still can be optimized out later. } - const DataLayout &DL = OrigIns->getModule()->getDataLayout(); - unsigned TypeSizeInBits = DL.getTypeSizeInBits(ConvertedShadow->getType()); unsigned SizeIndex = TypeSizeToSizeIndex(TypeSizeInBits); if (AsCall && SizeIndex < kNumberOfAccessSizes && !MS.CompileKernel) { diff --git a/llvm/test/Instrumentation/MemorySanitizer/check-constant-shadow.ll b/llvm/test/Instrumentation/MemorySanitizer/check-constant-shadow.ll --- a/llvm/test/Instrumentation/MemorySanitizer/check-constant-shadow.ll +++ b/llvm/test/Instrumentation/MemorySanitizer/check-constant-shadow.ll @@ -46,3 +46,32 @@ ; CONST: store i32 0, ; CHECK: store i32 undef, ; CHECK: ret void + + +; This function stores known initialized value, but msan can't prove this. +define i32 @MaybeUninitialized(<2 x i64> noundef %acc) nounwind uwtable sanitize_memory { +entry: + %shift = shufflevector <2 x i64> %acc, <2 x i64> poison, <2 x i32> + %0 = add <2 x i64> %shift, %acc + %1 = bitcast <2 x i64> %0 to <4 x i32> + %conv = extractelement <4 x i32> %1, i64 0 + ret i32 %conv +} + +; CHECK-LABEL: @MaybeUninitialized +; CHECK: store i32 extractelement (<4 x i32> bitcast (<2 x i64> to <4 x i32>), i64 0), i32* bitcast ([100 x i64]* @__msan_retval_tls to i32*), align 8 +; CHECK: store i32 0, i32* @__msan_retval_origin_tls + +; This function stores known initialized value, but msan can't prove this. +define noundef i32 @MaybeUninitializedRetNoUndef(<2 x i64> noundef %acc) nounwind uwtable sanitize_memory { +entry: + %shift = shufflevector <2 x i64> %acc, <2 x i64> poison, <2 x i32> + %0 = add <2 x i64> %shift, %acc + %1 = bitcast <2 x i64> %0 to <4 x i32> + %conv = extractelement <4 x i32> %1, i64 0 + ret i32 %conv +} + +; CHECK-LABEL: @MaybeUninitializedRetNoUndef +; CONST: br i1 icmp ne (i32 extractelement (<4 x i32> bitcast (<2 x i64> to <4 x i32>), i64 0), i32 0) +; CONST: call void @__msan_warning_with_origin_noreturn