Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions llvm/include/llvm/IR/InstrTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1559,6 +1559,11 @@ class CallBase : public Instruction {
Attrs = Attrs.addDereferenceableParamAttr(getContext(), i, Bytes);
}

/// adds the dereferenceable attribute to the list of attributes.
void addDereferenceableOrNullParamAttr(unsigned i, uint64_t Bytes) {
Attrs = Attrs.addDereferenceableOrNullParamAttr(getContext(), i, Bytes);
}

/// adds the dereferenceable attribute to the list of attributes.
void addDereferenceableRetAttr(uint64_t Bytes) {
Attrs = Attrs.addDereferenceableRetAttr(getContext(), Bytes);
Expand Down
17 changes: 17 additions & 0 deletions llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,22 @@ static void shortenAssignment(Instruction *Inst, Value *OriginalDest,
for_each(LinkedDVRAssigns, InsertAssignForOverlap);
}

// Helper to trim or drop any dereferencable/dereferencable_or_null attributes
// for a given argument, based on the new access being restricted to derefence
// bytes in the range [Offset, Offset+Size).
static void trimDereferencableAttrs(AnyMemIntrinsic *Intrinsic, unsigned Arg,
uint64_t Offset, uint64_t Size) {
uint64_t End = Offset + Size;
if (Intrinsic->getParamDereferenceableBytes(Arg) >= End)
Intrinsic->addDereferenceableParamAttr(Arg, Size);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're going to actually adjust the attributes, I'd expect to see something like "OldDerefenceableBytes - Offset" here, so that information about larger dereferenceability than the memset length is preserved.

But really, I'd consider to just completely drop the attributes in this transform. memset with a constant length already implies dereferenceability by itself.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thanks. I wasn't quite sure if dropping the attributes could have some downsides, but just dropping them is simpler so I like that solution. So I've updated the patch to just drop the attributes instead of trying to adjust them.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably we should drop all attributes here, so we don't need to adjust this whenever we add a new attribute to LLVM.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropping all attributes would also lose alignment, which is correctly adjusted and might not be recoverable...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see some alternatives:

  1. Instead of having an explicit set of attributes to drop we could use prepare a set of attributes that is safe to keep. And then use that for the filtering. That would more future proof in case new attributes are added.
  2. Another idea is to add some kind of support in Attributes.h (or similar). Such as a more centralized helper method to "filter attributes based on access being narrowed" (and then it might be easier to find and update that when adding new attributes). This could also just be an AttributeMask similar to getUBImplyingAttributes().

else
Intrinsic->removeParamAttr(Arg, Attribute::Dereferenceable);
if (Intrinsic->getParamDereferenceableOrNullBytes(Arg) >= End)
Intrinsic->addDereferenceableOrNullParamAttr(Arg, Size);
else
Intrinsic->removeParamAttr(Arg, Attribute::DereferenceableOrNull);
}

static bool tryToShorten(Instruction *DeadI, int64_t &DeadStart,
uint64_t &DeadSize, int64_t KillingStart,
uint64_t KillingSize, bool IsOverwriteEnd) {
Expand Down Expand Up @@ -644,6 +660,7 @@ static bool tryToShorten(Instruction *DeadI, int64_t &DeadStart,
DeadI->getIterator());
NewDestGEP->setDebugLoc(DeadIntrinsic->getDebugLoc());
DeadIntrinsic->setDest(NewDestGEP);
trimDereferencableAttrs(DeadIntrinsic, 0, ToRemoveSize, NewSize);
}

// Update attached dbg.assign intrinsics. Assume 8-bit byte.
Expand Down
30 changes: 30 additions & 0 deletions llvm/test/Transforms/DeadStoreElimination/OverwriteStoreBegin.ll
Original file line number Diff line number Diff line change
Expand Up @@ -402,3 +402,33 @@ entry:
store i64 1, ptr %p, align 1
ret void
}

; Verify that we adjust 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 dereferenceable(24) [[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 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 dereferenceable_or_null(20) [[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
}