https://github.com/dingxiangfei2009 updated https://github.com/llvm/llvm-project/pull/188001
>From 2f740fea6bd7613d3daff364bd850a98d95b1ea7 Mon Sep 17 00:00:00 2001 From: Xiangfei Ding <[email protected]> Date: Thu, 19 Mar 2026 16:04:41 +0000 Subject: [PATCH 1/5] MSan: poison the default-init allocation before calling constructors This change is to align with the standards pertaining to reserved global placement `new`s in the default initialisation style. Signed-off-by: Xiangfei Ding <[email protected]> --- clang/lib/CodeGen/CGExprCXX.cpp | 94 +++++++++++++++++++ .../test/CodeGenCXX/sanitize-default-init.cpp | 41 ++++++++ 2 files changed, 135 insertions(+) create mode 100644 clang/test/CodeGenCXX/sanitize-default-init.cpp diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index c585523f2718f..c05ab0a7cdd31 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -17,8 +17,11 @@ #include "CodeGenFunction.h" #include "ConstantEmitter.h" #include "TargetInfo.h" +#include "clang/AST/ExprCXX.h" #include "clang/Basic/CodeGenOptions.h" +#include "clang/Basic/Sanitizers.h" #include "clang/CodeGen/CGFunctionInfo.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/Intrinsics.h" using namespace clang; @@ -1489,6 +1492,7 @@ class CallDeleteDuringNew final : public EHScopeStack::Cleanup { EmitNewDeleteCall(CGF, OperatorDelete, FPT, DeleteArgs); } }; + } // namespace /// Enter a cleanup to call 'operator delete' if the initializer in a @@ -1553,6 +1557,86 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF, const CXXNewExpr *E, CGF.initFullExprCleanup(); } +namespace { +void PoisonTrivialField(CodeGenFunction &CGF, QualType const &Ty, + Address Dest) { + CharUnits Size = CGF.getContext().getTypeSizeInChars(Ty); + llvm::Value *SizeVal = CGF.CGM.getSize(Size); + llvm::Value *PoisonByte = llvm::PoisonValue::get(CGF.Builder.getInt8Ty()); + CGF.Builder.CreateMemSet(Dest, PoisonByte, SizeVal, Ty.isVolatileQualified()); +} + +void PoisonArrayLValue(CodeGenFunction &CGF, QualType const &ElementQualTy, + llvm::Type *ElementTy, LValue const &Dest, + llvm::Value *numElements); + +void PoisonLValueRecursive(CodeGenFunction &CGF, QualType const &Ty, + LValue const &Dest) { + if (Ty.isTriviallyCopyableType(CGF.getContext()) || Ty->isReferenceType()) { + return PoisonTrivialField(CGF, Ty, Dest.getAddress()); + } + + auto *RD = Ty->castAsCXXRecordDecl(); + assert(RD && + "type is not trivially copyable but it is not a record type either"); + for (auto *FD : RD->fields()) { + // There is no need to poison unnamed fields. + if (FD->isUnnamedBitField()) { + continue; + } + QualType FieldTy = FD->getType(); + LValue FieldLV = CGF.EmitLValueForField(Dest, FD); + if (FieldTy->isRecordType()) { + return PoisonLValueRecursive(CGF, FieldTy, FieldLV); + } + if (auto *AQualTy = dyn_cast<clang::ArrayType>(FieldTy)) { + if (auto *ATy = + dyn_cast<llvm::ArrayType>(CGF.ConvertTypeForMem(FieldTy))) { + if (uint64_t NumArrayElements = ATy->getNumElements()) { + PoisonArrayLValue( + CGF, AQualTy->getElementType(), ATy->getElementType(), FieldLV, + llvm::ConstantInt::get(CGF.SizeTy, NumArrayElements)); + } + } + return; + } + // Every other case is trivial to poison. + PoisonTrivialField(CGF, FieldTy, FieldLV.getAddress()); + } +} + +void PoisonArrayLValue(CodeGenFunction &CGF, QualType const &ElementQualTy, + llvm::Type *ElementTy, LValue const &Dest, + llvm::Value *NumElements) { + auto ElementAlign = Dest.getAlignment().alignmentOfArrayElement( + CGF.getContext().getTypeSizeInChars(ElementQualTy)); + + auto &Builder = CGF.Builder; + llvm::Value *BeginPtr = Dest.emitRawPointer(CGF); + llvm::Value *EndPtr = Builder.CreateInBoundsGEP( + ElementTy, BeginPtr, NumElements, "arraypoison.end"); + llvm::Value *One = llvm::ConstantInt::get(CGF.SizeTy, 1); + auto *EntryBB = Builder.GetInsertBlock(); + // The loop head. + auto *BodyBB = CGF.createBasicBlock("arraypoison.body"); + CGF.EmitBlock(BodyBB); + auto *CurElementPtr = + Builder.CreatePHI(BeginPtr->getType(), 2, "arraypoison.cur"); + CurElementPtr->addIncoming(BeginPtr, EntryBB); + LValue ElementDest = CGF.MakeAddrLValue( + Address(CurElementPtr, ElementTy, ElementAlign), ElementQualTy); + PoisonLValueRecursive(CGF, ElementQualTy, ElementDest); + llvm::Value *NextElementPtr = Builder.CreateInBoundsGEP( + ElementTy, CurElementPtr, One, "arraypoison.next"); + llvm::Value *Done = + Builder.CreateICmpEQ(NextElementPtr, EndPtr, "arraypoison.done"); + auto *EndBB = CGF.createBasicBlock("arraypoison.end"); + Builder.CreateCondBr(Done, EndBB, BodyBB); + CurElementPtr->addIncoming(NextElementPtr, Builder.GetInsertBlock()); + CGF.EmitBlock(EndBB); +} +} // namespace + llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // The element type being allocated. QualType allocType = getContext().getBaseElementType(E->getAllocatedType()); @@ -1611,6 +1695,16 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { allocatorArgs.add(RValue::get(allocation, *this), arg->getType()); } + if (E->getInitializationStyle() == CXXNewInitializationStyle::None && + SanOpts.has(SanitizerKind::Memory)) { + auto *ElemTy = ConvertTypeForMem(allocType); + auto Dest = MakeAddrLValue(allocation.withElementType(ElemTy), allocType); + if (numElements) { + PoisonArrayLValue(*this, allocType, ElemTy, Dest, numElements); + } else { + PoisonLValueRecursive(*this, allocType, Dest); + } + } } else { const FunctionProtoType *allocatorType = allocator->getType()->castAs<FunctionProtoType>(); diff --git a/clang/test/CodeGenCXX/sanitize-default-init.cpp b/clang/test/CodeGenCXX/sanitize-default-init.cpp new file mode 100644 index 0000000000000..fc3c2fd658fc6 --- /dev/null +++ b/clang/test/CodeGenCXX/sanitize-default-init.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -x c++ -fsanitize=memory -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s + +/// Sanitise the placement new with default initialisation style. + +namespace std { + using size_t = decltype(sizeof(0)); +} + +void *operator new(std::size_t, void *p) noexcept { return p; } + +struct Simple { + int x; +}; + +struct WithCtor { + int x; + int y[4]; + WithCtor() { + bool flag = x > 0; /// This is UB + } +}; + +// CHECK-LABEL: define {{.*}} i32 @main() +int main() { + { + Simple s; + // CHECK: [[S:%.+]] = alloca %struct.Simple, align 4 + // CHECK: [[W:%.+]] = alloca %struct.WithCtor, align 4 + s.x = 42; + // CHECK: {{%.+}} = call ptr @__msan_memset(ptr [[S]], i32 poison, i64 4) + new (&s) Simple; + bool flag = s.x == 42; /// This is UB + } + { + WithCtor w; + w.x = 42; + // CHECK: {{%.+}} = call ptr @__msan_memset(ptr [[W]], i32 poison, i64 20) + auto *ptr = new (&w) WithCtor; /// This is UB + // CHECK: call void @_ZN8WithCtorC1Ev + } +} >From cb45ffc8ef8d0446af9a860c110e3a8a29c43288 Mon Sep 17 00:00:00 2001 From: Xiangfei Ding <[email protected]> Date: Wed, 25 Mar 2026 14:28:01 +0000 Subject: [PATCH 2/5] undef in msan Signed-off-by: Xiangfei Ding <[email protected]> --- clang/lib/CodeGen/CGExprCXX.cpp | 37 +++++++++---------- .../test/CodeGenCXX/sanitize-default-init.cpp | 4 +- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index c05ab0a7cdd31..ac78a0e648099 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -1558,22 +1558,21 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF, const CXXNewExpr *E, } namespace { -void PoisonTrivialField(CodeGenFunction &CGF, QualType const &Ty, - Address Dest) { +void UndefTrivialField(CodeGenFunction &CGF, QualType const &Ty, Address Dest) { CharUnits Size = CGF.getContext().getTypeSizeInChars(Ty); llvm::Value *SizeVal = CGF.CGM.getSize(Size); - llvm::Value *PoisonByte = llvm::PoisonValue::get(CGF.Builder.getInt8Ty()); - CGF.Builder.CreateMemSet(Dest, PoisonByte, SizeVal, Ty.isVolatileQualified()); + llvm::Value *UndefByte = llvm::UndefValue::get(CGF.Builder.getInt8Ty()); + CGF.Builder.CreateMemSet(Dest, UndefByte, SizeVal, Ty.isVolatileQualified()); } -void PoisonArrayLValue(CodeGenFunction &CGF, QualType const &ElementQualTy, - llvm::Type *ElementTy, LValue const &Dest, - llvm::Value *numElements); +void UndefArrayLValue(CodeGenFunction &CGF, QualType const &ElementQualTy, + llvm::Type *ElementTy, LValue const &Dest, + llvm::Value *numElements); -void PoisonLValueRecursive(CodeGenFunction &CGF, QualType const &Ty, - LValue const &Dest) { +void UndefLValueRecursive(CodeGenFunction &CGF, QualType const &Ty, + LValue const &Dest) { if (Ty.isTriviallyCopyableType(CGF.getContext()) || Ty->isReferenceType()) { - return PoisonTrivialField(CGF, Ty, Dest.getAddress()); + return UndefTrivialField(CGF, Ty, Dest.getAddress()); } auto *RD = Ty->castAsCXXRecordDecl(); @@ -1587,13 +1586,13 @@ void PoisonLValueRecursive(CodeGenFunction &CGF, QualType const &Ty, QualType FieldTy = FD->getType(); LValue FieldLV = CGF.EmitLValueForField(Dest, FD); if (FieldTy->isRecordType()) { - return PoisonLValueRecursive(CGF, FieldTy, FieldLV); + return UndefLValueRecursive(CGF, FieldTy, FieldLV); } if (auto *AQualTy = dyn_cast<clang::ArrayType>(FieldTy)) { if (auto *ATy = dyn_cast<llvm::ArrayType>(CGF.ConvertTypeForMem(FieldTy))) { if (uint64_t NumArrayElements = ATy->getNumElements()) { - PoisonArrayLValue( + UndefArrayLValue( CGF, AQualTy->getElementType(), ATy->getElementType(), FieldLV, llvm::ConstantInt::get(CGF.SizeTy, NumArrayElements)); } @@ -1601,13 +1600,13 @@ void PoisonLValueRecursive(CodeGenFunction &CGF, QualType const &Ty, return; } // Every other case is trivial to poison. - PoisonTrivialField(CGF, FieldTy, FieldLV.getAddress()); + UndefTrivialField(CGF, FieldTy, FieldLV.getAddress()); } } -void PoisonArrayLValue(CodeGenFunction &CGF, QualType const &ElementQualTy, - llvm::Type *ElementTy, LValue const &Dest, - llvm::Value *NumElements) { +void UndefArrayLValue(CodeGenFunction &CGF, QualType const &ElementQualTy, + llvm::Type *ElementTy, LValue const &Dest, + llvm::Value *NumElements) { auto ElementAlign = Dest.getAlignment().alignmentOfArrayElement( CGF.getContext().getTypeSizeInChars(ElementQualTy)); @@ -1625,7 +1624,7 @@ void PoisonArrayLValue(CodeGenFunction &CGF, QualType const &ElementQualTy, CurElementPtr->addIncoming(BeginPtr, EntryBB); LValue ElementDest = CGF.MakeAddrLValue( Address(CurElementPtr, ElementTy, ElementAlign), ElementQualTy); - PoisonLValueRecursive(CGF, ElementQualTy, ElementDest); + UndefLValueRecursive(CGF, ElementQualTy, ElementDest); llvm::Value *NextElementPtr = Builder.CreateInBoundsGEP( ElementTy, CurElementPtr, One, "arraypoison.next"); llvm::Value *Done = @@ -1700,9 +1699,9 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { auto *ElemTy = ConvertTypeForMem(allocType); auto Dest = MakeAddrLValue(allocation.withElementType(ElemTy), allocType); if (numElements) { - PoisonArrayLValue(*this, allocType, ElemTy, Dest, numElements); + UndefArrayLValue(*this, allocType, ElemTy, Dest, numElements); } else { - PoisonLValueRecursive(*this, allocType, Dest); + UndefLValueRecursive(*this, allocType, Dest); } } } else { diff --git a/clang/test/CodeGenCXX/sanitize-default-init.cpp b/clang/test/CodeGenCXX/sanitize-default-init.cpp index fc3c2fd658fc6..04245fdcf33bd 100644 --- a/clang/test/CodeGenCXX/sanitize-default-init.cpp +++ b/clang/test/CodeGenCXX/sanitize-default-init.cpp @@ -27,14 +27,14 @@ int main() { // CHECK: [[S:%.+]] = alloca %struct.Simple, align 4 // CHECK: [[W:%.+]] = alloca %struct.WithCtor, align 4 s.x = 42; - // CHECK: {{%.+}} = call ptr @__msan_memset(ptr [[S]], i32 poison, i64 4) + // CHECK: {{%.+}} = call ptr @__msan_memset(ptr [[S]], i32 undef, i64 4) new (&s) Simple; bool flag = s.x == 42; /// This is UB } { WithCtor w; w.x = 42; - // CHECK: {{%.+}} = call ptr @__msan_memset(ptr [[W]], i32 poison, i64 20) + // CHECK: {{%.+}} = call ptr @__msan_memset(ptr [[W]], i32 undef, i64 20) auto *ptr = new (&w) WithCtor; /// This is UB // CHECK: call void @_ZN8WithCtorC1Ev } >From f836c2fac383b6e38ee39c625797debb2c3def96 Mon Sep 17 00:00:00 2001 From: Xiangfei Ding <[email protected]> Date: Thu, 16 Apr 2026 20:02:20 +0000 Subject: [PATCH 3/5] old behaviour on undef memset Signed-off-by: Xiangfei Ding <[email protected]> --- .../InstCombine/memset-load-forward.ll | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 llvm/test/Transforms/InstCombine/memset-load-forward.ll diff --git a/llvm/test/Transforms/InstCombine/memset-load-forward.ll b/llvm/test/Transforms/InstCombine/memset-load-forward.ll new file mode 100644 index 0000000000000..7989122ac25ac --- /dev/null +++ b/llvm/test/Transforms/InstCombine/memset-load-forward.ll @@ -0,0 +1,17 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +define i32 @test_load_forward(ptr %p) { +; CHECK-LABEL: @test_load_forward( +; CHECK-NEXT: store i32 100, ptr [[P:%.*]], align 4 +; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(4) [[P]], i8 undef, i64 4, i1 false) +; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4 +; CHECK-NEXT: ret i32 [[V]] +; + store i32 100, ptr %p, align 4 + call void @llvm.memset.p0.i64(ptr %p, i8 undef, i64 4, i1 false) + %v = load i32, ptr %p, align 4 + ret i32 %v +} + +declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1) >From 1abeb11047ac02f194a8e86f9ebc5f5ad8c247bb Mon Sep 17 00:00:00 2001 From: Xiangfei Ding <[email protected]> Date: Wed, 25 Mar 2026 14:28:01 +0000 Subject: [PATCH 4/5] preserve undef in middle-end Signed-off-by: Xiangfei Ding <[email protected]> --- llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 4 ++++ llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 12 +++++++----- llvm/test/Transforms/InstCombine/memset.ll | 2 ++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 0b7d8b7946f99..ae9033ed5ca39 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -10082,6 +10082,10 @@ SDValue SelectionDAG::getMemset(SDValue Chain, const SDLoc &dl, SDValue Dst, const CallInst *CI, MachinePointerInfo DstPtrInfo, const AAMDNodes &AAInfo) { + // Optimize non-volatile memset with an undef value to a no-op. + if (Src.isUndef() && !isVol) + return Chain; + // Check to see if we should lower the memset to stores first. // For cases within the target-specified limits, this is the best choice. ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index a622e0248fce8..60d5873ff8660 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -239,11 +239,13 @@ Instruction *InstCombinerImpl::SimplifyAnyMemSet(AnyMemSetInst *MI) { // Remove memset with an undef value. // FIXME: This is technically incorrect because it might overwrite a poison // value. Change to PoisonValue once #52930 is resolved. - if (isa<UndefValue>(MI->getValue())) { - // Set the size of the copy to 0, it will be deleted on the next iteration. - MI->setLength((uint64_t)0); - return MI; - } + // Postponed to SelectionDAG lowering phase. + // if (isa<UndefValue>(MI->getValue())) { + // // Set the size of the copy to 0, it will be deleted on the next iteration. + // MI->setLength((uint64_t)0); + // return MI; + // } + // Extract the length and alignment and fill if they are constant. ConstantInt *LenC = dyn_cast<ConstantInt>(MI->getLength()); diff --git a/llvm/test/Transforms/InstCombine/memset.ll b/llvm/test/Transforms/InstCombine/memset.ll index d593db040476f..b0935d6f5649e 100644 --- a/llvm/test/Transforms/InstCombine/memset.ll +++ b/llvm/test/Transforms/InstCombine/memset.ll @@ -31,6 +31,7 @@ define void @memset_to_constant() { ; value. Stop folding it once #52930 is resolved. define void @memset_undef(ptr %p) { ; CHECK-LABEL: @memset_undef( +; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr noundef nonnull align 1 dereferenceable(8) [[P:%.*]], i8 undef, i32 8, i1 false) ; CHECK-NEXT: ret void ; call void @llvm.memset.p0.i32(ptr %p, i8 undef, i32 8, i1 false) @@ -48,6 +49,7 @@ define void @memset_undef_volatile(ptr %p) { define void @memset_poison(ptr %p) { ; CHECK-LABEL: @memset_poison( +; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr noundef nonnull align 1 dereferenceable(8) [[P:%.*]], i8 poison, i32 8, i1 false) ; CHECK-NEXT: ret void ; call void @llvm.memset.p0.i32(ptr %p, i8 poison, i32 8, i1 false) >From ee85899304af55d4542d31ae94e4713d2f20eb35 Mon Sep 17 00:00:00 2001 From: Xiangfei Ding <[email protected]> Date: Thu, 16 Apr 2026 20:43:13 +0000 Subject: [PATCH 5/5] new behaviour when undef memsets are preserved Signed-off-by: Xiangfei Ding <[email protected]> --- .../test/CodeGenCXX/sanitize-default-init.cpp | 4 ++-- .../Instrumentation/MemorySanitizer.cpp | 21 +++++++++++++------ .../InstCombine/memset-load-forward.ll | 5 ++--- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/clang/test/CodeGenCXX/sanitize-default-init.cpp b/clang/test/CodeGenCXX/sanitize-default-init.cpp index 04245fdcf33bd..551a402f33921 100644 --- a/clang/test/CodeGenCXX/sanitize-default-init.cpp +++ b/clang/test/CodeGenCXX/sanitize-default-init.cpp @@ -27,14 +27,14 @@ int main() { // CHECK: [[S:%.+]] = alloca %struct.Simple, align 4 // CHECK: [[W:%.+]] = alloca %struct.WithCtor, align 4 s.x = 42; - // CHECK: {{%.+}} = call ptr @__msan_memset(ptr [[S]], i32 undef, i64 4) + // CHECK: call void @__msan_poison(ptr [[S]], i64 4) new (&s) Simple; bool flag = s.x == 42; /// This is UB } { WithCtor w; w.x = 42; - // CHECK: {{%.+}} = call ptr @__msan_memset(ptr [[W]], i32 undef, i64 20) + // CHECK: call void @__msan_poison(ptr [[W]], i64 20) auto *ptr = new (&w) WithCtor; /// This is UB // CHECK: call void @_ZN8WithCtorC1Ev } diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp index f128ff5cfaab6..d7297d0299ac1 100644 --- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -716,7 +716,7 @@ class MemorySanitizer { FunctionCallee MsanSetOriginFn; /// MSan runtime replacements for memmove, memcpy and memset. - FunctionCallee MemmoveFn, MemcpyFn, MemsetFn; + FunctionCallee MemmoveFn, MemcpyFn, MemsetFn, MsanPoisonFn; /// KMSAN callback for task-local function argument shadow. StructType *MsanContextStateTy; @@ -1015,6 +1015,8 @@ void MemorySanitizer::initializeCallbacks(Module &M, MemsetFn = M.getOrInsertFunction("__msan_memset", TLI.getAttrList(C, {1}, /*Signed=*/true), PtrTy, PtrTy, IRB.getInt32Ty(), IntptrTy); + MsanPoisonFn = M.getOrInsertFunction("__msan_poison", IRB.getVoidTy(), PtrTy, + IntptrTy); MsanInstrumentAsmStoreFn = M.getOrInsertFunction( "__msan_instrument_asm_store", IRB.getVoidTy(), PtrTy, IntptrTy); @@ -3325,11 +3327,18 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { // Same as memcpy. void visitMemSetInst(MemSetInst &I) { IRBuilder<> IRB(&I); - IRB.CreateCall( - MS.MemsetFn, - {I.getArgOperand(0), - IRB.CreateIntCast(I.getArgOperand(1), IRB.getInt32Ty(), false), - IRB.CreateIntCast(I.getArgOperand(2), MS.IntptrTy, false)}); + Value *Val = I.getArgOperand(1); + if (isa<UndefValue>(Val)) { + IRB.CreateCall(MS.MsanPoisonFn, + {I.getArgOperand(0), + IRB.CreateIntCast(I.getArgOperand(2), MS.IntptrTy, false)}); + } else { + IRB.CreateCall( + MS.MemsetFn, + {I.getArgOperand(0), + IRB.CreateIntCast(Val, IRB.getInt32Ty(), false), + IRB.CreateIntCast(I.getArgOperand(2), MS.IntptrTy, false)}); + } I.eraseFromParent(); } diff --git a/llvm/test/Transforms/InstCombine/memset-load-forward.ll b/llvm/test/Transforms/InstCombine/memset-load-forward.ll index 7989122ac25ac..03765399eecc0 100644 --- a/llvm/test/Transforms/InstCombine/memset-load-forward.ll +++ b/llvm/test/Transforms/InstCombine/memset-load-forward.ll @@ -1,10 +1,9 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=instcombine -S | FileCheck %s +; RUN: opt < %s -passes="instcombine,dse" -S | FileCheck %s define i32 @test_load_forward(ptr %p) { ; CHECK-LABEL: @test_load_forward( -; CHECK-NEXT: store i32 100, ptr [[P:%.*]], align 4 -; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(4) [[P]], i8 undef, i64 4, i1 false) +; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(4) [[P:%.*]], i8 undef, i64 4, i1 false) ; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4 ; CHECK-NEXT: ret i32 [[V]] ; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
