[llvm] 361b536 - [Attributor] Simplify switches with more than one potential condition

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 17 22:43:04 PDT 2023


Author: Johannes Doerfert
Date: 2023-08-17T22:42:38-07:00
New Revision: 361b536bbc678b59cf1391346bb6613f1ab4f00c

URL: https://github.com/llvm/llvm-project/commit/361b536bbc678b59cf1391346bb6613f1ab4f00c
DIFF: https://github.com/llvm/llvm-project/commit/361b536bbc678b59cf1391346bb6613f1ab4f00c.diff

LOG: [Attributor] Simplify switches with more than one potential condition

Before, we allowed the condition to be simplified to a simple constant
only, otherwise we assumed all successors are live. Now we allow
multiple constants, and mark the default successor as dead accordingly.

Added: 
    

Modified: 
    llvm/lib/Transforms/IPO/AttributorAttributes.cpp
    llvm/test/Transforms/Attributor/value-simplify.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 4633f9b796941e..987345b32feb05 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -4776,23 +4776,53 @@ identifyAliveSuccessors(Attributor &A, const SwitchInst &SI,
                         AbstractAttribute &AA,
                         SmallVectorImpl<const Instruction *> &AliveSuccessors) {
   bool UsedAssumedInformation = false;
-  std::optional<Constant *> C =
-      A.getAssumedConstant(*SI.getCondition(), AA, UsedAssumedInformation);
-  if (!C || isa_and_nonnull<UndefValue>(*C)) {
-    // No value yet, assume all edges are dead.
-  } else if (isa_and_nonnull<ConstantInt>(*C)) {
-    for (const auto &CaseIt : SI.cases()) {
-      if (CaseIt.getCaseValue() == *C) {
-        AliveSuccessors.push_back(&CaseIt.getCaseSuccessor()->front());
-        return UsedAssumedInformation;
-      }
-    }
-    AliveSuccessors.push_back(&SI.getDefaultDest()->front());
+  SmallVector<AA::ValueAndContext> Values;
+  if (!A.getAssumedSimplifiedValues(IRPosition::value(*SI.getCondition()), &AA,
+                                    Values, AA::AnyScope,
+                                    UsedAssumedInformation)) {
+    // Something went wrong, assume all successors are live.
+    for (const BasicBlock *SuccBB : successors(SI.getParent()))
+      AliveSuccessors.push_back(&SuccBB->front());
+    return false;
+  }
+
+  if (Values.empty() ||
+      (Values.size() == 1 &&
+       isa_and_nonnull<UndefValue>(Values.front().getValue()))) {
+    // No valid value yet, assume all edges are dead.
     return UsedAssumedInformation;
-  } else {
+  }
+
+  Type &Ty = *SI.getCondition()->getType();
+  SmallPtrSet<ConstantInt *, 8> Constants;
+  auto CheckForConstantInt = [&](Value *V) {
+    if (auto *CI = dyn_cast_if_present<ConstantInt>(AA::getWithType(*V, Ty))) {
+      Constants.insert(CI);
+      return true;
+    }
+    return false;
+  };
+
+  if (!all_of(Values, [&](AA::ValueAndContext &VAC) {
+        return CheckForConstantInt(VAC.getValue());
+      })) {
     for (const BasicBlock *SuccBB : successors(SI.getParent()))
       AliveSuccessors.push_back(&SuccBB->front());
+    return UsedAssumedInformation;
   }
+
+  unsigned MatchedCases = 0;
+  for (const auto &CaseIt : SI.cases()) {
+    if (Constants.count(CaseIt.getCaseValue())) {
+      ++MatchedCases;
+      AliveSuccessors.push_back(&CaseIt.getCaseSuccessor()->front());
+    }
+  }
+
+  // If all potential values have been matched, we will not visit the default
+  // case.
+  if (MatchedCases < Constants.size())
+    AliveSuccessors.push_back(&SI.getDefaultDest()->front());
   return UsedAssumedInformation;
 }
 

diff  --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll
index 56d6f4c33ecb45..c3f0e6676e514c 100644
--- a/llvm/test/Transforms/Attributor/value-simplify.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify.ll
@@ -1505,6 +1505,134 @@ define i1 @constexpr_icmp2() {
   ret i1 icmp eq (ptr addrspacecast (ptr addrspace(4) @str to ptr), ptr null)
 }
 
+define i8 @switch(i1 %c1, i1 %c2) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define {{[^@]+}}@switch
+; TUNIT-SAME: (i1 noundef [[C1:%.*]], i1 [[C2:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    br i1 [[C1]], label [[T:%.*]], label [[F:%.*]]
+; TUNIT:       t:
+; TUNIT-NEXT:    br label [[M:%.*]]
+; TUNIT:       f:
+; TUNIT-NEXT:    br label [[M]]
+; TUNIT:       m:
+; TUNIT-NEXT:    [[J:%.*]] = phi i32 [ 0, [[T]] ], [ 4, [[F]] ]
+; TUNIT-NEXT:    switch i32 [[J]], label [[DEFAULT1:%.*]] [
+; TUNIT-NEXT:    i32 1, label [[DEAD1:%.*]]
+; TUNIT-NEXT:    i32 2, label [[DEAD2:%.*]]
+; TUNIT-NEXT:    i32 3, label [[DEAD3:%.*]]
+; TUNIT-NEXT:    i32 4, label [[ALIVE1:%.*]]
+; TUNIT-NEXT:    ]
+; TUNIT:       default1:
+; TUNIT-NEXT:    br label [[ALIVE1]]
+; TUNIT:       alive1:
+; TUNIT-NEXT:    [[K:%.*]] = phi i32 [ 1, [[M]] ], [ 4, [[DEFAULT1]] ]
+; TUNIT-NEXT:    switch i32 [[K]], label [[DEAD4:%.*]] [
+; TUNIT-NEXT:    i32 1, label [[END1:%.*]]
+; TUNIT-NEXT:    i32 2, label [[DEAD5:%.*]]
+; TUNIT-NEXT:    i32 4, label [[END2:%.*]]
+; TUNIT-NEXT:    ]
+; TUNIT:       end1:
+; TUNIT-NEXT:    ret i8 -1
+; TUNIT:       end2:
+; TUNIT-NEXT:    ret i8 -2
+; TUNIT:       dead1:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       dead2:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       dead3:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       dead4:
+; TUNIT-NEXT:    unreachable
+; TUNIT:       dead5:
+; TUNIT-NEXT:    unreachable
+;
+; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define {{[^@]+}}@switch
+; CGSCC-SAME: (i1 noundef [[C1:%.*]], i1 [[C2:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    br i1 [[C1]], label [[T:%.*]], label [[F:%.*]]
+; CGSCC:       t:
+; CGSCC-NEXT:    br label [[M:%.*]]
+; CGSCC:       f:
+; CGSCC-NEXT:    br label [[M]]
+; CGSCC:       m:
+; CGSCC-NEXT:    [[J:%.*]] = phi i32 [ 0, [[T]] ], [ 4, [[F]] ]
+; CGSCC-NEXT:    switch i32 [[J]], label [[DEFAULT1:%.*]] [
+; CGSCC-NEXT:    i32 1, label [[DEAD1:%.*]]
+; CGSCC-NEXT:    i32 2, label [[DEAD2:%.*]]
+; CGSCC-NEXT:    i32 3, label [[DEAD3:%.*]]
+; CGSCC-NEXT:    i32 4, label [[ALIVE1:%.*]]
+; CGSCC-NEXT:    ]
+; CGSCC:       default1:
+; CGSCC-NEXT:    br label [[ALIVE1]]
+; CGSCC:       alive1:
+; CGSCC-NEXT:    [[K:%.*]] = phi i32 [ 1, [[M]] ], [ 4, [[DEFAULT1]] ]
+; CGSCC-NEXT:    switch i32 [[K]], label [[DEAD4:%.*]] [
+; CGSCC-NEXT:    i32 1, label [[END1:%.*]]
+; CGSCC-NEXT:    i32 2, label [[DEAD5:%.*]]
+; CGSCC-NEXT:    i32 4, label [[END2:%.*]]
+; CGSCC-NEXT:    ]
+; CGSCC:       end1:
+; CGSCC-NEXT:    ret i8 -1
+; CGSCC:       end2:
+; CGSCC-NEXT:    ret i8 -2
+; CGSCC:       dead1:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       dead2:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       dead3:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       dead4:
+; CGSCC-NEXT:    unreachable
+; CGSCC:       dead5:
+; CGSCC-NEXT:    unreachable
+;
+entry:
+  br i1 %c1, label %t, label %f
+
+t:
+  br label %m
+
+f:
+  br label %m
+
+m:
+  %j = phi i32 [ 0, %t ], [ 4, %f ]
+  switch i32 %j, label %default1 [
+  i32 1, label %dead1
+  i32 2, label %dead2
+  i32 3, label %dead3
+  i32 4, label %alive1
+  ]
+
+default1:
+  br label %alive1
+
+alive1:
+  %k = phi i32 [ 1, %m ], [ 4, %default1 ]
+  switch i32 %k, label %dead4 [
+  i32 1, label %end1
+  i32 2, label %dead5
+  i32 4, label %end2
+  ]
+
+end1:
+  ret i8 -1
+end2:
+  ret i8 -2
+dead1:
+  ret i8 1
+dead2:
+  ret i8 2
+dead3:
+  ret i8 3
+dead4:
+  ret i8 4
+dead5:
+  ret i8 5
+}
+
 ;.
 ; TUNIT: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
 ; TUNIT: attributes #[[ATTR1]] = { memory(readwrite, argmem: none) }


        


More information about the llvm-commits mailing list