[llvm] goldsteinn/attrs preserve non eq (PR #111014)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 3 09:19:48 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: None (goldsteinn)
<details>
<summary>Changes</summary>
- **[SimplifyCFG] Add tests for preserving some not exactly equal attrs; NFC**
- **[SimplifyCFG][Attributes] Preserve some non-equal attrs when intersecting**
---
Full diff: https://github.com/llvm/llvm-project/pull/111014.diff
3 Files Affected:
- (modified) llvm/lib/IR/Attributes.cpp (+50-5)
- (modified) llvm/test/Transforms/SimplifyCFG/hoist-cb-diff-attrs.ll (+25-2)
- (modified) llvm/test/Transforms/SimplifyCFG/sink-cb-diff-attrs.ll (+27-2)
``````````diff
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index f2ba61ae51039e..aa5fdb48b74643 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -973,20 +973,28 @@ AttributeSet::intersectWith(LLVMContext &C, AttributeSet Other) const {
// Loop through all attributes in both this and Other in sorted order. If
// the attribute is only present in one of the sets, it will be set in
// Attr0. If it is present in both sets both Attr0 and Attr1 will be set.
+ // If the attr is only present in one of the sets, WithoutCur will point to
+ // the set that doesn't contain Attr0.
Attribute Attr0, Attr1;
- if (ItBegin1 == ItEnd1)
+ const AttributeSet *WithoutCur = nullptr;
+ if (ItBegin1 == ItEnd1) {
+ WithoutCur = &Other;
Attr0 = *ItBegin0++;
- else if (ItBegin0 == ItEnd0)
+ } else if (ItBegin0 == ItEnd0) {
+ WithoutCur = this;
Attr0 = *ItBegin1++;
- else {
+ } else {
int Cmp = ItBegin0->cmpKind(*ItBegin1);
if (Cmp == 0) {
Attr0 = *ItBegin0++;
Attr1 = *ItBegin1++;
- } else if (Cmp < 0)
+ } else if (Cmp < 0) {
+ WithoutCur = &Other;
Attr0 = *ItBegin0++;
- else
+ } else {
+ WithoutCur = this;
Attr0 = *ItBegin1++;
+ }
}
assert(Attr0.isValid() && "Iteration should always yield a valid attr");
@@ -1011,14 +1019,51 @@ AttributeSet::intersectWith(LLVMContext &C, AttributeSet Other) const {
// If we don't have both attributes, then fail if the attribute is
// must-preserve or drop it otherwise.
if (!Attr1.isValid()) {
+ assert(WithoutCur != nullptr &&
+ "Iteration with only one valid attr didn't set WithoutCur");
if (Attribute::intersectMustPreserve(Kind))
return std::nullopt;
+
+ // We can preserve some attributes without it being present in both this
+ // and Other. For example the intersection between ReadOnly and ReadNone
+ // is ReadOnly.
+ // NB: MemoryEffects don't need this extra logic. The `&` operator already
+ // does this type of intersection and missing memory effects implies
+ // unknown which we can't union.
+ switch (Kind) {
+ // ReadOnly + ReadNone -> ReadOnly
+ case Attribute::ReadOnly:
+ if (WithoutCur->hasAttribute(Attribute::ReadNone))
+ Intersected.addAttribute(Attr0);
+ break;
+ // ReadNone + ReadOnly -> ReadNone
+ case Attribute::ReadNone:
+ if (WithoutCur->hasAttribute(Attribute::ReadOnly))
+ Intersected.addAttribute(Attribute::ReadOnly);
+ break;
+ // Dereferenceable + DereferenceableOrNull -> DereferenceableOrNull
+ case Attribute::DereferenceableOrNull:
+ case Attribute::Dereferenceable: {
+ Attribute::AttrKind OtherKind = Kind == Attribute::Dereferenceable
+ ? Attribute::DereferenceableOrNull
+ : Attribute::Dereferenceable;
+ Attr1 = WithoutCur->getAttribute(OtherKind);
+ if (Attr1.isValid()) {
+ uint64_t NewVal =
+ std::min(Attr0.getValueAsInt(), Attr1.getValueAsInt());
+ Intersected.addRawIntAttr(Attribute::DereferenceableOrNull, NewVal);
+ }
+ } break;
+ default:
+ break;
+ }
continue;
}
// We have both attributes so apply the intersection rule.
assert(Attr1.hasKindAsEnum() && Kind == Attr1.getKindAsEnum() &&
"Iterator picked up two different attributes in the same iteration");
+ assert(WithoutCur == nullptr && "Iteration two valid attrs set WithoutCur");
// Attribute we can intersect with "and"
if (Attribute::intersectWithAnd(Kind)) {
diff --git a/llvm/test/Transforms/SimplifyCFG/hoist-cb-diff-attrs.ll b/llvm/test/Transforms/SimplifyCFG/hoist-cb-diff-attrs.ll
index ee6c0cfd43b253..079a86cf321ea0 100644
--- a/llvm/test/Transforms/SimplifyCFG/hoist-cb-diff-attrs.ll
+++ b/llvm/test/Transforms/SimplifyCFG/hoist-cb-diff-attrs.ll
@@ -30,7 +30,7 @@ else:
define ptr @test_hoist_int_attrs2(i1 %c, ptr %p, i64 %x) {
; CHECK-LABEL: define {{[^@]+}}@test_hoist_int_attrs2
; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]], i64 [[X:%.*]]) {
-; CHECK-NEXT: [[R:%.*]] = call ptr @foo(ptr dereferenceable(50) [[P]], i64 range(i64 10, 1000) [[X]]) #[[ATTR1:[0-9]+]]
+; CHECK-NEXT: [[R:%.*]] = call ptr @foo(ptr dereferenceable(50) dereferenceable_or_null(50) [[P]], i64 range(i64 10, 1000) [[X]]) #[[ATTR1:[0-9]+]]
; CHECK-NEXT: br i1 [[C]], label [[COMMON_RET:%.*]], label [[ELSE:%.*]]
; CHECK: common.ret:
; CHECK-NEXT: ret ptr [[R]]
@@ -49,10 +49,33 @@ else:
ret ptr %r2
}
+define ptr @test_hoist_int_attrs3(i1 %c, ptr %p, ptr %p2, i64 %x) {
+; CHECK-LABEL: define {{[^@]+}}@test_hoist_int_attrs3
+; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]], ptr [[P2:%.*]], i64 [[X:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = call ptr @foo2(ptr align 32 dereferenceable_or_null(100) [[P]], ptr align 32 dereferenceable_or_null(100) [[P2]], i64 range(i64 10, 100000) [[X]]) #[[ATTR0]]
+; CHECK-NEXT: br i1 [[C]], label [[COMMON_RET:%.*]], label [[ELSE:%.*]]
+; CHECK: common.ret:
+; CHECK-NEXT: ret ptr [[R]]
+; CHECK: else:
+; CHECK-NEXT: call void @side.effect()
+; CHECK-NEXT: br label [[COMMON_RET]]
+;
+ br i1 %c, label %if, label %else
+if:
+ %r = call ptr @foo2(ptr align 64 dereferenceable(100) %p, ptr dereferenceable(500) align 64 %p2, i64 range(i64 10, 1000) %x) memory(read)
+ ret ptr %r
+
+else:
+ %r2 = call ptr @foo2(ptr align 32 dereferenceable_or_null(200) %p, ptr dereferenceable_or_null(100) align 32 %p2, i64 range(i64 10000, 100000) %x) memory(write)
+ call void @side.effect()
+ ret ptr %r2
+}
+
+
define ptr @test_hoist_bool_attrs2(i1 %c, ptr %p, i64 %x) {
; CHECK-LABEL: define {{[^@]+}}@test_hoist_bool_attrs2
; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]], i64 [[X:%.*]]) {
-; CHECK-NEXT: [[R:%.*]] = call noundef ptr @foo(ptr nonnull [[P]], i64 noundef [[X]]) #[[ATTR2:[0-9]+]]
+; CHECK-NEXT: [[R:%.*]] = call noundef ptr @foo(ptr nonnull readonly [[P]], i64 noundef [[X]]) #[[ATTR2:[0-9]+]]
; CHECK-NEXT: br i1 [[C]], label [[COMMON_RET:%.*]], label [[ELSE:%.*]]
; CHECK: common.ret:
; CHECK-NEXT: ret ptr [[R]]
diff --git a/llvm/test/Transforms/SimplifyCFG/sink-cb-diff-attrs.ll b/llvm/test/Transforms/SimplifyCFG/sink-cb-diff-attrs.ll
index fe9d87080dd111..bb9a43aa48b02f 100644
--- a/llvm/test/Transforms/SimplifyCFG/sink-cb-diff-attrs.ll
+++ b/llvm/test/Transforms/SimplifyCFG/sink-cb-diff-attrs.ll
@@ -93,7 +93,7 @@ define ptr @test_sink_int_attrs2(i1 %c, ptr %p, i64 %x) {
; CHECK-NEXT: call void @side.effect()
; CHECK-NEXT: br label [[END]]
; CHECK: end:
-; CHECK-NEXT: [[R2:%.*]] = call ptr @foo(ptr dereferenceable(50) [[P]], i64 range(i64 10, 1000) [[X]]) #[[ATTR2:[0-9]+]]
+; CHECK-NEXT: [[R2:%.*]] = call ptr @foo(ptr dereferenceable(50) dereferenceable_or_null(50) [[P]], i64 range(i64 10, 1000) [[X]]) #[[ATTR2:[0-9]+]]
; CHECK-NEXT: ret ptr [[R2]]
;
br i1 %c, label %if, label %else
@@ -110,6 +110,31 @@ end:
ret ptr %pr
}
+define ptr @test_sink_int_attrs3(i1 %c, ptr %p, i64 %x) {
+; CHECK-LABEL: define {{[^@]+}}@test_sink_int_attrs3
+; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]], i64 [[X:%.*]]) {
+; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[END:%.*]]
+; CHECK: if:
+; CHECK-NEXT: call void @side.effect()
+; CHECK-NEXT: br label [[END]]
+; CHECK: end:
+; CHECK-NEXT: [[R2:%.*]] = call ptr @foo(ptr dereferenceable_or_null(50) [[P]], i64 range(i64 10, 1000) [[X]]) #[[ATTR2]]
+; CHECK-NEXT: ret ptr [[R2]]
+;
+ br i1 %c, label %if, label %else
+if:
+ call void @side.effect()
+ %r = call ptr @foo(ptr dereferenceable_or_null(50) %p, i64 range(i64 10, 1000) %x) memory(read)
+ br label %end
+
+else:
+ %r2 = call ptr @foo(ptr dereferenceable(100) align 32 %p, i64 range(i64 11, 100) %x) memory(none)
+ br label %end
+end:
+ %pr = phi ptr [ %r, %if], [%r2, %else]
+ ret ptr %pr
+}
+
define ptr @test_sink_bool_attrs2(i1 %c, ptr %p, i64 %x) {
; CHECK-LABEL: define {{[^@]+}}@test_sink_bool_attrs2
; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]], i64 [[X:%.*]]) {
@@ -118,7 +143,7 @@ define ptr @test_sink_bool_attrs2(i1 %c, ptr %p, i64 %x) {
; CHECK-NEXT: call void @side.effect()
; CHECK-NEXT: br label [[END]]
; CHECK: end:
-; CHECK-NEXT: [[R2:%.*]] = call noundef ptr @foo(ptr nonnull [[P]], i64 noundef [[X]]) #[[ATTR3:[0-9]+]]
+; CHECK-NEXT: [[R2:%.*]] = call noundef ptr @foo(ptr nonnull readonly [[P]], i64 noundef [[X]]) #[[ATTR3:[0-9]+]]
; CHECK-NEXT: ret ptr [[R2]]
;
br i1 %c, label %if, label %else
``````````
</details>
https://github.com/llvm/llvm-project/pull/111014
More information about the llvm-commits
mailing list