[llvm] goldsteinn/early diff attrs (PR #110929)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 2 13:58:58 PDT 2024
https://github.com/goldsteinn created https://github.com/llvm/llvm-project/pull/110929
- **[EarlyCSE] Add tests for de-duplication of callsites with differing attrs; NFC**
- **[EarlyCSE] De-Duplicate callsites with differing attrs**
>From 073552c285227cf5b1b81bf382457bf5d10c4137 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Wed, 2 Oct 2024 15:53:27 -0500
Subject: [PATCH 1/2] [EarlyCSE] Add tests for de-duplication of callsites with
differing attrs; NFC
---
.../EarlyCSE/replace-calls-def-attrs.ll | 127 ++++++++++++++++++
1 file changed, 127 insertions(+)
create mode 100644 llvm/test/Transforms/EarlyCSE/replace-calls-def-attrs.ll
diff --git a/llvm/test/Transforms/EarlyCSE/replace-calls-def-attrs.ll b/llvm/test/Transforms/EarlyCSE/replace-calls-def-attrs.ll
new file mode 100644
index 00000000000000..173d0b573aff4d
--- /dev/null
+++ b/llvm/test/Transforms/EarlyCSE/replace-calls-def-attrs.ll
@@ -0,0 +1,127 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals all --version 5
+; RUN: opt -S -passes=early-cse < %s | FileCheck %s
+
+declare i8 @baz(i8, i8) readnone
+declare i8 @buz(i8, i8)
+define i8 @same_parent_combine_diff_attrs(i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]])
+; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]])
+; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %c1 = call i8 @baz(i8 %x, i8 noundef %y)
+ %c0 = call i8 @baz(i8 noundef %x, i8 noundef %y)
+ %r = call i8 @buz(i8 %c0, i8 %c1)
+ ret i8 %r
+
+}
+
+define i8 @diff_parent_combine_diff_attrs(i1 %c, i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @diff_parent_combine_diff_attrs(
+; CHECK-SAME: i1 [[C:%.*]], i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]])
+; CHECK-NEXT: br i1 [[C]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]])
+; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
+; CHECK-NEXT: ret i8 [[R]]
+; CHECK: [[F]]:
+; CHECK-NEXT: [[R2:%.*]] = add i8 [[C1]], 4
+; CHECK-NEXT: ret i8 [[R2]]
+;
+ %c1 = call i8 @baz(i8 %x, i8 noundef %y)
+ br i1 %c, label %T, label %F
+T:
+ %c0 = call i8 @baz(i8 noundef %x, i8 noundef %y)
+ %r = call i8 @buz(i8 %c0, i8 %c1)
+ ret i8 %r
+F:
+ %r2 = add i8 %c1, 4
+ ret i8 %r2
+}
+
+define i8 @same_parent_combine_diff_attrs_todo(i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs_todo(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]])
+; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR1:[0-9]+]]
+; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %c1 = call i8 @baz(i8 %x, i8 noundef %y)
+ %c0 = call i8 @baz(i8 noundef %x, i8 noundef %y) alwaysinline
+ %r = call i8 @buz(i8 %c0, i8 %c1)
+ ret i8 %r
+
+}
+
+define i8 @same_parent_combine_diff_attrs_fail(i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs_fail(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]])
+; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR2:[0-9]+]]
+; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %c1 = call i8 @baz(i8 %x, i8 noundef %y)
+ %c0 = call i8 @baz(i8 noundef %x, i8 noundef %y) strictfp
+ %r = call i8 @buz(i8 %c0, i8 %c1)
+ ret i8 %r
+
+}
+
+define i8 @diff_parent_combine_diff_attrs_todo(i1 %c, i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @diff_parent_combine_diff_attrs_todo(
+; CHECK-SAME: i1 [[C:%.*]], i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]])
+; CHECK-NEXT: br i1 [[C]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR3:[0-9]+]]
+; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
+; CHECK-NEXT: ret i8 [[R]]
+; CHECK: [[F]]:
+; CHECK-NEXT: [[R2:%.*]] = add i8 [[C1]], 4
+; CHECK-NEXT: ret i8 [[R2]]
+;
+ %c1 = call i8 @baz(i8 %x, i8 noundef %y)
+ br i1 %c, label %T, label %F
+T:
+ %c0 = call i8 @baz(i8 noundef %x, i8 noundef %y) optnone noinline
+ %r = call i8 @buz(i8 %c0, i8 %c1)
+ ret i8 %r
+F:
+ %r2 = add i8 %c1, 4
+ ret i8 %r2
+}
+
+define i8 @diff_parent_combine_diff_attrs_fail(i1 %c, i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @diff_parent_combine_diff_attrs_fail(
+; CHECK-SAME: i1 [[C:%.*]], i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]])
+; CHECK-NEXT: br i1 [[C]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR2]]
+; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
+; CHECK-NEXT: ret i8 [[R]]
+; CHECK: [[F]]:
+; CHECK-NEXT: [[R2:%.*]] = add i8 [[C1]], 4
+; CHECK-NEXT: ret i8 [[R2]]
+;
+ %c1 = call i8 @baz(i8 %x, i8 noundef %y)
+ br i1 %c, label %T, label %F
+T:
+ %c0 = call i8 @baz(i8 noundef %x, i8 noundef %y) strictfp
+ %r = call i8 @buz(i8 %c0, i8 %c1)
+ ret i8 %r
+F:
+ %r2 = add i8 %c1, 4
+ ret i8 %r2
+}
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { memory(none) }
+; CHECK: attributes #[[ATTR1]] = { alwaysinline }
+; CHECK: attributes #[[ATTR2]] = { strictfp }
+; CHECK: attributes #[[ATTR3]] = { noinline optnone }
+;.
>From ba98d3c4fcbeab1edc179fa9fa05ec0aa12a8e0f Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Wed, 2 Oct 2024 15:53:17 -0500
Subject: [PATCH 2/2] [EarlyCSE] De-Duplicate callsites with differing attrs
We only do this if the attributes of the two callsites are compatible
(intersectable) which is probably not in fact necessary.
---
llvm/include/llvm/IR/Instruction.h | 3 ++-
llvm/lib/IR/Instruction.cpp | 5 +++--
llvm/lib/Transforms/Scalar/EarlyCSE.cpp | 9 ++++++---
llvm/test/Transforms/EarlyCSE/replace-calls-def-attrs.ll | 6 ++----
4 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index 61dba265dc948b..c6084fa762be08 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -876,7 +876,8 @@ class Instruction : public User,
/// Return true if the specified instruction is exactly identical to the
/// current one. This means that all operands match and any extra information
/// (e.g. load is volatile) agree.
- bool isIdenticalTo(const Instruction *I) const LLVM_READONLY;
+ bool isIdenticalTo(const Instruction *I,
+ bool IntersectAttrs = false) const LLVM_READONLY;
/// This is like isIdenticalTo, except that it ignores the
/// SubclassOptionalData flags, which may specify conditions under which the
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index eec751078698b2..d9b47351bf543d 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -862,8 +862,9 @@ bool Instruction::hasSameSpecialState(const Instruction *I2,
return true;
}
-bool Instruction::isIdenticalTo(const Instruction *I) const {
- return isIdenticalToWhenDefined(I) &&
+bool Instruction::isIdenticalTo(const Instruction *I,
+ bool IntersectAttrs) const {
+ return isIdenticalToWhenDefined(I, IntersectAttrs) &&
SubclassOptionalData == I->SubclassOptionalData;
}
diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
index cf11f5bc885a75..223f307e1baf08 100644
--- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
+++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -362,7 +362,7 @@ static bool isEqualImpl(SimpleValue LHS, SimpleValue RHS) {
if (LHSI->getOpcode() != RHSI->getOpcode())
return false;
- if (LHSI->isIdenticalToWhenDefined(RHSI)) {
+ if (LHSI->isIdenticalToWhenDefined(RHSI, /*IntersectAttrs=*/true)) {
// Convergent calls implicitly depend on the set of threads that is
// currently executing, so conservatively return false if they are in
// different basic blocks.
@@ -551,7 +551,7 @@ bool DenseMapInfo<CallValue>::isEqual(CallValue LHS, CallValue RHS) {
if (LHSI->isConvergent() && LHSI->getParent() != RHSI->getParent())
return false;
- return LHSI->isIdenticalTo(RHSI);
+ return LHSI->isIdenticalTo(RHSI, /*IntersectAttrs=*/true);
}
//===----------------------------------------------------------------------===//
@@ -621,7 +621,7 @@ bool DenseMapInfo<GEPValue>::isEqual(const GEPValue &LHS, const GEPValue &RHS) {
return false;
if (LHS.ConstantOffset.has_value() && RHS.ConstantOffset.has_value())
return LHS.ConstantOffset.value() == RHS.ConstantOffset.value();
- return LGEP->isIdenticalToWhenDefined(RGEP);
+ return LGEP->isIdenticalToWhenDefined(RGEP, /*IntersectAttrs=*/true);
}
//===----------------------------------------------------------------------===//
@@ -1632,6 +1632,9 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n");
continue;
}
+
+ // Potential TODO: We may be throwing away attribute information when
+ // we delete Inst that we could propagate too InVal.first.
if (!Inst.use_empty())
Inst.replaceAllUsesWith(InVal.first);
salvageKnowledge(&Inst, &AC);
diff --git a/llvm/test/Transforms/EarlyCSE/replace-calls-def-attrs.ll b/llvm/test/Transforms/EarlyCSE/replace-calls-def-attrs.ll
index 173d0b573aff4d..3b1f39bcf3498d 100644
--- a/llvm/test/Transforms/EarlyCSE/replace-calls-def-attrs.ll
+++ b/llvm/test/Transforms/EarlyCSE/replace-calls-def-attrs.ll
@@ -7,8 +7,7 @@ define i8 @same_parent_combine_diff_attrs(i8 %x, i8 %y) {
; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]])
-; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]])
-; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
+; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C1]], i8 [[C1]])
; CHECK-NEXT: ret i8 [[R]]
;
%c1 = call i8 @baz(i8 %x, i8 noundef %y)
@@ -24,8 +23,7 @@ define i8 @diff_parent_combine_diff_attrs(i1 %c, i8 %x, i8 %y) {
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]])
; CHECK-NEXT: br i1 [[C]], label %[[T:.*]], label %[[F:.*]]
; CHECK: [[T]]:
-; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]])
-; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
+; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C1]], i8 [[C1]])
; CHECK-NEXT: ret i8 [[R]]
; CHECK: [[F]]:
; CHECK-NEXT: [[R2:%.*]] = add i8 [[C1]], 4
More information about the llvm-commits
mailing list