Skip to content

Commit 6b014c5

Browse files
committed
[DSE] Update dereferenceable attributes when adjusting memintrinsic ptr
Consider IR like this call void @llvm.memset.p0.i64(ptr dereferenceable(28) %p, i8 0, i64 28, i1 false) store i32 1, ptr %p It has been optimized like this: %p2 = getelementptr inbounds i8, ptr %p, i64 4 call void @llvm.memset.p0.i64(ptr dereferenceable(28) %p2, i8 0, i64 24, i1 false) store i32 1, ptr %p As the input IR doesn't guarantee that it is OK to deref 28 bytes starting at the adjusted pointer %p2 the transformation has been a bit flawed. With this patch we make sure to also adjust the size of any dereferenceable/dereferenceable_or_null attributes when doing the transform in tryToShorten (when adjusting the start pointer). So now we will get dereferenceable(24) in the example above.
1 parent 2f40145 commit 6b014c5

File tree

3 files changed

+53
-0
lines changed

3 files changed

+53
-0
lines changed

llvm/include/llvm/IR/InstrTypes.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,11 @@ class CallBase : public Instruction {
15591559
Attrs = Attrs.addDereferenceableParamAttr(getContext(), i, Bytes);
15601560
}
15611561

1562+
/// adds the dereferenceable attribute to the list of attributes.
1563+
void addDereferenceableOrNullParamAttr(unsigned i, uint64_t Bytes) {
1564+
Attrs = Attrs.addDereferenceableOrNullParamAttr(getContext(), i, Bytes);
1565+
}
1566+
15621567
/// adds the dereferenceable attribute to the list of attributes.
15631568
void addDereferenceableRetAttr(uint64_t Bytes) {
15641569
Attrs = Attrs.addDereferenceableRetAttr(getContext(), Bytes);

llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,23 @@ static void shortenAssignment(Instruction *Inst, Value *OriginalDest,
563563
for_each(LinkedDVRAssigns, InsertAssignForOverlap);
564564
}
565565

566+
// Helper to trim or drop any dereferencable/dereferencable_or_null attributes
567+
// for a given argument, based on the new access being restricted to derefence
568+
// bytes in the range [Offset, Offset+Size).
569+
static void trimDereferencableAttrs(AnyMemIntrinsic *Intrinsic, unsigned Arg,
570+
uint64_t Offset, uint64_t Size) {
571+
uint64_t End = Offset + Size;
572+
if (Intrinsic->getParamDereferenceableBytes(Arg) >= End)
573+
Intrinsic->addDereferenceableParamAttr(Arg, Size);
574+
else
575+
Intrinsic->removeParamAttr(Arg, Attribute::Dereferenceable);
576+
if (Intrinsic->getParamDereferenceableOrNullBytes(Arg) >= End)
577+
Intrinsic->addDereferenceableOrNullParamAttr(Arg, Size);
578+
else
579+
Intrinsic->removeParamAttr(Arg, Attribute::DereferenceableOrNull);
580+
}
581+
582+
566583
static bool tryToShorten(Instruction *DeadI, int64_t &DeadStart,
567584
uint64_t &DeadSize, int64_t KillingStart,
568585
uint64_t KillingSize, bool IsOverwriteEnd) {
@@ -644,6 +661,7 @@ static bool tryToShorten(Instruction *DeadI, int64_t &DeadStart,
644661
DeadI->getIterator());
645662
NewDestGEP->setDebugLoc(DeadIntrinsic->getDebugLoc());
646663
DeadIntrinsic->setDest(NewDestGEP);
664+
trimDereferencableAttrs(DeadIntrinsic, 0, ToRemoveSize, NewSize);
647665
}
648666

649667
// Update attached dbg.assign intrinsics. Assume 8-bit byte.

llvm/test/Transforms/DeadStoreElimination/OverwriteStoreBegin.ll

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,3 +402,33 @@ entry:
402402
store i64 1, ptr %p, align 1
403403
ret void
404404
}
405+
406+
; Verify that we adjust the dereferenceable attribute.
407+
define void @dereferenceable(ptr nocapture %p) {
408+
; CHECK-LABEL: @dereferenceable(
409+
; CHECK-NEXT: entry:
410+
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 4
411+
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 dereferenceable(24) [[TMP0]], i8 0, i64 24, i1 false)
412+
; CHECK-NEXT: store i32 1, ptr [[P]], align 4
413+
; CHECK-NEXT: ret void
414+
;
415+
entry:
416+
call void @llvm.memset.p0.i64(ptr dereferenceable(28) align 4 %p, i8 0, i64 28, i1 false)
417+
store i32 1, ptr %p, align 4
418+
ret void
419+
}
420+
421+
; Verify that we adjust the dereferenceable_or_null attribute.
422+
define void @dereferenceable_or_null(ptr nocapture %p) {
423+
; CHECK-LABEL: @dereferenceable_or_null(
424+
; CHECK-NEXT: entry:
425+
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 8
426+
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 dereferenceable_or_null(20) [[TMP0]], i8 0, i64 20, i1 false)
427+
; CHECK-NEXT: store i64 1, ptr [[P]], align 4
428+
; CHECK-NEXT: ret void
429+
;
430+
entry:
431+
call void @llvm.memset.p0.i64(ptr dereferenceable_or_null(28) align 4 %p, i8 0, i64 28, i1 false)
432+
store i64 1, ptr %p, align 4
433+
ret void
434+
}

0 commit comments

Comments
 (0)