diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp index 13f3de07c3c44..deebec4f6ee81 100644 --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -50,6 +50,7 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Argument.h" +#include "llvm/IR/AttributeMask.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" #include "llvm/IR/ConstantRangeList.h" @@ -563,6 +564,43 @@ static void shortenAssignment(Instruction *Inst, Value *OriginalDest, for_each(LinkedDVRAssigns, InsertAssignForOverlap); } +/// Update the attributes given that a memory access is updated (the +/// dereferenced pointer could be moved forward when shortening a +/// mem intrinsic). +static void adjustArgAttributes(AnyMemIntrinsic *Intrinsic, unsigned ArgNo, + uint64_t PtrOffset) { + // Remember old attributes. + AttributeSet OldAttrs = Intrinsic->getParamAttributes(ArgNo); + + // Find attributes that should be kept, and remove the rest. + AttributeMask AttrsToRemove; + for (auto &Attr : OldAttrs) { + if (Attr.hasKindAsEnum()) { + switch (Attr.getKindAsEnum()) { + default: + break; + case Attribute::Alignment: + // Only keep alignment if PtrOffset satisfy the alignment. + if (isAligned(Attr.getAlignment().valueOrOne(), PtrOffset)) + continue; + break; + case Attribute::Dereferenceable: + case Attribute::DereferenceableOrNull: + // We could reduce the size of these attributes according to + // PtrOffset. But we simply drop these for now. + break; + case Attribute::NonNull: + case Attribute::NoUndef: + continue; + } + } + AttrsToRemove.addAttribute(Attr); + } + + // Remove the attributes that should be dropped. + Intrinsic->removeParamAttrs(ArgNo, AttrsToRemove); +} + static bool tryToShorten(Instruction *DeadI, int64_t &DeadStart, uint64_t &DeadSize, int64_t KillingStart, uint64_t KillingSize, bool IsOverwriteEnd) { @@ -644,6 +682,7 @@ static bool tryToShorten(Instruction *DeadI, int64_t &DeadStart, DeadI->getIterator()); NewDestGEP->setDebugLoc(DeadIntrinsic->getDebugLoc()); DeadIntrinsic->setDest(NewDestGEP); + adjustArgAttributes(DeadIntrinsic, 0, ToRemoveSize); } // Update attached dbg.assign intrinsics. Assume 8-bit byte. diff --git a/llvm/test/Transforms/DeadStoreElimination/OverwriteStoreBegin.ll b/llvm/test/Transforms/DeadStoreElimination/OverwriteStoreBegin.ll index bc1756f6ca9d1..43fbcfcc600c6 100644 --- a/llvm/test/Transforms/DeadStoreElimination/OverwriteStoreBegin.ll +++ b/llvm/test/Transforms/DeadStoreElimination/OverwriteStoreBegin.ll @@ -402,3 +402,33 @@ entry: store i64 1, ptr %p, align 1 ret void } + +; Verify that we adjust/drop the dereferenceable attribute. +define void @dereferenceable(ptr nocapture %p) { +; CHECK-LABEL: @dereferenceable( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 4 +; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[TMP0]], i8 0, i64 24, i1 false) +; CHECK-NEXT: store i32 1, ptr [[P]], align 4 +; CHECK-NEXT: ret void +; +entry: + call void @llvm.memset.p0.i64(ptr dereferenceable(28) align 4 %p, i8 0, i64 28, i1 false) + store i32 1, ptr %p, align 4 + ret void +} + +; Verify that we adjust/drop the dereferenceable_or_null attribute. +define void @dereferenceable_or_null(ptr nocapture %p) { +; CHECK-LABEL: @dereferenceable_or_null( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 8 +; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[TMP0]], i8 0, i64 20, i1 false) +; CHECK-NEXT: store i64 1, ptr [[P]], align 4 +; CHECK-NEXT: ret void +; +entry: + call void @llvm.memset.p0.i64(ptr dereferenceable_or_null(28) align 4 %p, i8 0, i64 28, i1 false) + store i64 1, ptr %p, align 4 + ret void +}