[LVI] Check for non-speculatable instructions
authorNikita Popov <npopov@redhat.com>
Fri, 13 Jan 2023 15:07:06 +0000 (16:07 +0100)
committerNikita Popov <npopov@redhat.com>
Fri, 13 Jan 2023 15:10:12 +0000 (16:10 +0100)
When constraining an operand based on a condition at a (potentially
transitive) use site, make sure we don't skip over non-speculatable
instructions. While the result is only used under the condition,
the non-speculatable instruction may have a side-effect or UB.

Demonstrating this issue requires raising the limit on the walk,
so do that.

llvm/lib/Analysis/LazyValueInfo.cpp
llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll

index d49e18a..f1587ce 100644 (file)
@@ -1660,7 +1660,7 @@ ConstantRange LazyValueInfo::getConstantRangeAtUse(const Use &U,
   // position where V can be constrained by a select or branch condition.
   const Use *CurrU = &U;
   // TODO: Increase limit?
-  const unsigned MaxUsesToInspect = 2;
+  const unsigned MaxUsesToInspect = 3;
   for (unsigned I = 0; I < MaxUsesToInspect; ++I) {
     std::optional<ValueLatticeElement> CondVal;
     auto *CurrI = cast<Instruction>(CurrU->getUser());
@@ -1673,6 +1673,11 @@ ConstantRange LazyValueInfo::getConstantRangeAtUse(const Use &U,
       // TODO: Use non-local query?
       CondVal =
           getEdgeValueLocal(V, PHI->getIncomingBlock(*CurrU), PHI->getParent());
+    } else if (!isSafeToSpeculativelyExecute(CurrI)) {
+      // Stop walking if we hit a non-speculatable instruction. Even if the
+      // result is only used under a specific condition, executing the
+      // instruction itself may cause side effects or UB already.
+      break;
     }
     if (CondVal && CondVal->isConstantRange())
       CR = CR.intersectWith(CondVal->getConstantRange());
index fb1a03c..58d71b4 100644 (file)
@@ -74,12 +74,10 @@ define i16 @sel_true_cond_extra_use(i16 %x) {
   ret i16 %sel
 }
 
-; TODO: We could handle this case by raising the limit on the number of
-; instructions we look through.
 define i16 @sel_true_cond_chain_speculatable(i16 %x) {
 ; CHECK-LABEL: @sel_true_cond_chain_speculatable(
-; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.uadd.sat.i16(i16 [[X:%.*]], i16 1)
-; CHECK-NEXT:    [[EXTRA:%.*]] = mul i16 [[SUB]], 3
+; CHECK-NEXT:    [[SUB1:%.*]] = add nuw i16 [[X:%.*]], 1
+; CHECK-NEXT:    [[EXTRA:%.*]] = mul i16 [[SUB1]], 3
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i16 [[X]], -1
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[EXTRA]], i16 42
 ; CHECK-NEXT:    ret i16 [[SEL]]
@@ -106,6 +104,8 @@ define i16 @sel_true_cond_chain_non_speculatable(i16 %x) {
   ret i16 %sel
 }
 
+; TODO: We could handle this case by raising the limit on the number of
+; instructions we look through.
 define i16 @sel_true_cond_longer_chain(i16 %x) {
 ; CHECK-LABEL: @sel_true_cond_longer_chain(
 ; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.uadd.sat.i16(i16 [[X:%.*]], i16 1)