[llvm] 1848525 - [CodeMetrics] Don't require speculatability for ephemeral values

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 21 11:30:18 PDT 2021


Author: Nikita Popov
Date: 2021-10-21T20:30:01+02:00
New Revision: 184852584231c60156fb4ec7eddb228b13837c39

URL: https://github.com/llvm/llvm-project/commit/184852584231c60156fb4ec7eddb228b13837c39
DIFF: https://github.com/llvm/llvm-project/commit/184852584231c60156fb4ec7eddb228b13837c39.diff

LOG: [CodeMetrics] Don't require speculatability for ephemeral values

As discussed in D112016, our current requirement of speculatability
for ephemeral is overly strict: What we really care about is that
the instruction will be DCEd once the assume is dropped. For that
it is sufficient that the instruction is side-effect free and not
a terminator.

In particular, this allows non-dereferenceable loads to be ephemeral
values.

Differential Revision: https://reviews.llvm.org/D112179

Added: 
    

Modified: 
    llvm/lib/Analysis/CodeMetrics.cpp
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/lib/Transforms/Utils/SimplifyCFG.cpp
    llvm/test/Transforms/Inline/ephemeral.ll
    llvm/test/Transforms/SimplifyCFG/unprofitable-pr.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/CodeMetrics.cpp b/llvm/lib/Analysis/CodeMetrics.cpp
index 8c8e2ee6627fd..27c52506352ff 100644
--- a/llvm/lib/Analysis/CodeMetrics.cpp
+++ b/llvm/lib/Analysis/CodeMetrics.cpp
@@ -34,8 +34,9 @@ appendSpeculatableOperands(const Value *V,
 
   for (const Value *Operand : U->operands())
     if (Visited.insert(Operand).second)
-      if (isSafeToSpeculativelyExecute(Operand))
-        Worklist.push_back(Operand);
+      if (const auto *I = dyn_cast<Instruction>(Operand))
+        if (!I->mayHaveSideEffects() && !I->isTerminator())
+          Worklist.push_back(I);
 }
 
 static void completeEphemeralValues(SmallPtrSetImpl<const Value *> &Visited,

diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index bf1989c58c207..8991582a7a25b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -494,7 +494,9 @@ static bool isEphemeralValueOf(const Instruction *I, const Value *E) {
       if (V == E)
         return true;
 
-      if (V == I || isSafeToSpeculativelyExecute(V)) {
+      if (V == I || (isa<Instruction>(V) &&
+                     !cast<Instruction>(V)->mayHaveSideEffects() &&
+                     !cast<Instruction>(V)->isTerminator())) {
        EphValues.insert(V);
        if (const User *U = dyn_cast<User>(V))
          append_range(WorkSet, U->operands());

diff  --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 920df4e9d7421..84bf364d6d24a 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -2577,11 +2577,11 @@ static bool BlockIsSimpleEnoughToThreadThrough(BasicBlock *BB) {
   int Size = 0;
 
   SmallPtrSet<const Value *, 32> EphValues;
-  auto IsEphemeral = [&](const Value *V) {
-    if (isa<AssumeInst>(V))
+  auto IsEphemeral = [&](const Instruction *I) {
+    if (isa<AssumeInst>(I))
       return true;
-    return isSafeToSpeculativelyExecute(V) &&
-           all_of(V->users(),
+    return !I->mayHaveSideEffects() && !I->isTerminator() &&
+           all_of(I->users(),
                   [&](const User *U) { return EphValues.count(U); });
   };
 

diff  --git a/llvm/test/Transforms/Inline/ephemeral.ll b/llvm/test/Transforms/Inline/ephemeral.ll
index f47c349cb517b..b25d1e08148bd 100644
--- a/llvm/test/Transforms/Inline/ephemeral.ll
+++ b/llvm/test/Transforms/Inline/ephemeral.ll
@@ -26,10 +26,10 @@ define i32 @inner(i8* %y) {
   ret i32 %a1
 }
 
-; TODO: The load should be considered ephemeral here, even though it is not
-; speculatable.
+; Only the ret should be included in the instruction count, the load and icmp
+; are both ephemeral.
 ; CHECK: Analyzing call of inner2...
-; CHECK: NumInstructions: 2
+; CHECK: NumInstructions: 1
 define void @inner2(i8* %y) {
   %v = load i8, i8* %y
   %c = icmp eq i8 %v, 42

diff  --git a/llvm/test/Transforms/SimplifyCFG/unprofitable-pr.ll b/llvm/test/Transforms/SimplifyCFG/unprofitable-pr.ll
index af918657b5701..4f6107b122744 100644
--- a/llvm/test/Transforms/SimplifyCFG/unprofitable-pr.ll
+++ b/llvm/test/Transforms/SimplifyCFG/unprofitable-pr.ll
@@ -233,32 +233,37 @@ false2:                                           ; preds = %true1
   ret void
 }
 
-; TODO: The load should be considered ephemeral here, even though it is not
-; speculatable.
+; The load, icmp and assume should not count towards the limit, they are
+; ephemeral.
 define void @test_non_speculatable(i1 %c, i64* align 1 %ptr, i8* %ptr2) local_unnamed_addr #0 {
 ; CHECK-LABEL: @test_non_speculatable(
-; CHECK-NEXT:    br i1 [[C:%.*]], label [[TRUE1:%.*]], label [[FALSE1:%.*]]
-; CHECK:       true1:
+; CHECK-NEXT:    br i1 [[C:%.*]], label [[TRUE2_CRITEDGE:%.*]], label [[FALSE1:%.*]]
+; CHECK:       false1:
+; CHECK-NEXT:    store volatile i64 1, i64* [[PTR:%.*]], align 4
 ; CHECK-NEXT:    [[V:%.*]] = load i8, i8* [[PTR2:%.*]], align 1
 ; CHECK-NEXT:    [[C2:%.*]] = icmp eq i8 [[V]], 42
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
-; CHECK-NEXT:    store volatile i64 0, i64* [[PTR:%.*]], align 8
+; CHECK-NEXT:    store volatile i64 0, i64* [[PTR]], align 8
 ; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
 ; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
 ; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
 ; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
 ; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
-; CHECK-NEXT:    br i1 [[C]], label [[TRUE2:%.*]], label [[FALSE2:%.*]]
-; CHECK:       false1:
-; CHECK-NEXT:    store volatile i64 1, i64* [[PTR]], align 4
-; CHECK-NEXT:    br label [[TRUE1]]
+; CHECK-NEXT:    store volatile i64 3, i64* [[PTR]], align 8
+; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
 ; CHECK:       common.ret:
 ; CHECK-NEXT:    ret void
-; CHECK:       true2:
+; CHECK:       true2.critedge:
+; CHECK-NEXT:    [[V_C:%.*]] = load i8, i8* [[PTR2]], align 1
+; CHECK-NEXT:    [[C2_C:%.*]] = icmp eq i8 [[V_C]], 42
+; CHECK-NEXT:    call void @llvm.assume(i1 [[C2_C]])
+; CHECK-NEXT:    store volatile i64 0, i64* [[PTR]], align 8
+; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
+; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
+; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
+; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
+; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
 ; CHECK-NEXT:    store volatile i64 2, i64* [[PTR]], align 8
-; CHECK-NEXT:    br label [[COMMON_RET:%.*]]
-; CHECK:       false2:
-; CHECK-NEXT:    store volatile i64 3, i64* [[PTR]], align 8
 ; CHECK-NEXT:    br label [[COMMON_RET]]
 ;
   br i1 %c, label %true1, label %false1


        


More information about the llvm-commits mailing list