[llvm] 6c667ab - Recommit "[ValueTracking] Use knownbits interface for determining if `div`/`rem` are safe to speculate" (2nd Try)

Noah Goldstein via llvm-commits llvm-commits at lists.llvm.org
Mon May 1 15:24:07 PDT 2023


Author: Noah Goldstein
Date: 2023-05-01T17:23:58-05:00
New Revision: 6c667abf3294d61e4fbe1238e1755c79f7547f1b

URL: https://github.com/llvm/llvm-project/commit/6c667abf3294d61e4fbe1238e1755c79f7547f1b
DIFF: https://github.com/llvm/llvm-project/commit/6c667abf3294d61e4fbe1238e1755c79f7547f1b.diff

LOG: Recommit "[ValueTracking] Use knownbits interface for determining if `div`/`rem` are safe to speculate" (2nd Try)

Add `poison` checks that where missing.

Reviewed By: nikic

Added: 
    

Modified: 
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/test/Transforms/LICM/speculate-div.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index a5259ba7fbf31..c607767103687 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -6033,31 +6033,34 @@ bool llvm::isSafeToSpeculativelyExecuteWithOpcode(
   default:
     return true;
   case Instruction::UDiv:
-  case Instruction::URem: {
-    // x / y is undefined if y == 0.
-    const APInt *V;
-    if (match(Inst->getOperand(1), m_APInt(V)))
-      return *V != 0;
-    return false;
-  }
+  case Instruction::URem:
   case Instruction::SDiv:
   case Instruction::SRem: {
-    // x / y is undefined if y == 0 or x == INT_MIN and y == -1
-    const APInt *Numerator, *Denominator;
-    if (!match(Inst->getOperand(1), m_APInt(Denominator)))
-      return false;
-    // We cannot hoist this division if the denominator is 0.
-    if (*Denominator == 0)
+    // x / y is undefined if y == 0 or y is poison.
+    const DataLayout &DL = Inst->getModule()->getDataLayout();
+    if (!isGuaranteedNotToBePoison(Inst->getOperand(1), AC, CtxI, DT) ||
+        !isKnownNonZero(Inst->getOperand(1), DL, /*Depth*/ 0, AC, CtxI, DT))
       return false;
+
+    // Unsigned case only needs to avoid denominator == 0 or poison.
+    if (Opcode == Instruction::UDiv || Opcode == Instruction::URem)
+      return true;
+
+    // x s/ y is also undefined if x == INT_MIN and y == -1
+    KnownBits KnownDenominator =
+        computeKnownBits(Inst->getOperand(1), DL, /*Depth*/ 0, AC, CtxI, DT);
+
     // It's safe to hoist if the denominator is not 0 or -1.
-    if (!Denominator->isAllOnes())
+    if (!KnownDenominator.Zero.isZero())
       return true;
-    // At this point we know that the denominator is -1.  It is safe to hoist as
-    // long we know that the numerator is not INT_MIN.
-    if (match(Inst->getOperand(0), m_APInt(Numerator)))
-      return !Numerator->isMinSignedValue();
-    // The numerator *might* be MinSignedValue.
-    return false;
+
+    // At this point denominator may be -1.  It is safe to hoist as
+    // long we know that the numerator is neither poison nor INT_MIN.
+    if (!isGuaranteedNotToBePoison(Inst->getOperand(0), AC, CtxI, DT))
+      return false;
+    KnownBits KnownNumerator =
+        computeKnownBits(Inst->getOperand(0), DL, /*Depth*/ 0, AC, CtxI, DT);
+    return !KnownNumerator.getSignedMinValue().isMinSignedValue();
   }
   case Instruction::Load: {
     const LoadInst *LI = dyn_cast<LoadInst>(Inst);

diff  --git a/llvm/test/Transforms/LICM/speculate-div.ll b/llvm/test/Transforms/LICM/speculate-div.ll
index 50e755ef7083e..fde63e43d0164 100644
--- a/llvm/test/Transforms/LICM/speculate-div.ll
+++ b/llvm/test/Transforms/LICM/speculate-div.ll
@@ -4,7 +4,7 @@
 declare void @maythrow()
 declare void @use(i16)
 
-define void @sdiv_not_ok(i16 %n, i16 %xx) {
+define void @sdiv_not_ok(i16 %n, i16 noundef %xx) {
 ; CHECK-LABEL: @sdiv_not_ok(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[X:%.*]] = or i16 [[XX:%.*]], 1
@@ -25,7 +25,7 @@ loop:
   br label %loop
 }
 
-define void @srem_not_ok2(i16 %nn, i16 %x) {
+define void @srem_not_ok2(i16 %nn, i16 noundef %x) {
 ; CHECK-LABEL: @srem_not_ok2(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[N:%.*]] = and i16 [[NN:%.*]], 1323
@@ -46,15 +46,15 @@ loop:
   br label %loop
 }
 
-define void @sdiv_ok(i16 %n, i16 %xx) {
+define void @sdiv_ok(i16 %n, i16 noundef %xx) {
 ; CHECK-LABEL: @sdiv_ok(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[XO:%.*]] = or i16 [[XX:%.*]], 1
 ; CHECK-NEXT:    [[X:%.*]] = and i16 [[XO]], 123
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i16 [[N:%.*]], [[X]]
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    call void @maythrow()
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv i16 [[N:%.*]], [[X]]
 ; CHECK-NEXT:    call void @use(i16 [[DIV]])
 ; CHECK-NEXT:    br label [[LOOP]]
 ;
@@ -69,15 +69,15 @@ loop:
   br label %loop
 }
 
-define void @srem_ok2(i16 %nn, i16 %xx) {
+define void @srem_ok2(i16 noundef %nn, i16 noundef %xx) {
 ; CHECK-LABEL: @srem_ok2(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[N:%.*]] = and i16 [[NN:%.*]], 123
 ; CHECK-NEXT:    [[X:%.*]] = or i16 [[XX:%.*]], 1
+; CHECK-NEXT:    [[DIV:%.*]] = srem i16 [[N]], [[X]]
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    call void @maythrow()
-; CHECK-NEXT:    [[DIV:%.*]] = srem i16 [[N]], [[X]]
 ; CHECK-NEXT:    call void @use(i16 [[DIV]])
 ; CHECK-NEXT:    br label [[LOOP]]
 ;
@@ -92,7 +92,53 @@ loop:
   br label %loop
 }
 
-define void @udiv_not_ok(i16 %n, i16 %xx) {
+define void @sdiv_not_ok3_maybe_poison_denum(i16 noundef %nn, i16 %xx) {
+; CHECK-LABEL: @sdiv_not_ok3_maybe_poison_denum(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[N:%.*]] = and i16 [[NN:%.*]], 123
+; CHECK-NEXT:    [[X:%.*]] = or i16 [[XX:%.*]], 1
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    call void @maythrow()
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i16 [[N]], [[X]]
+; CHECK-NEXT:    call void @use(i16 [[DIV]])
+; CHECK-NEXT:    br label [[LOOP]]
+;
+entry:
+  %n = and i16 %nn, 123
+  %x = or i16 %xx, 1
+  br label %loop
+loop:
+  call void @maythrow()
+  %div = sdiv i16 %n, %x
+  call void @use(i16 %div)
+  br label %loop
+}
+
+define void @sdiv_not_ok3_maybe_poison_num(i16 %nn, i16 noundef  %xx) {
+; CHECK-LABEL: @sdiv_not_ok3_maybe_poison_num(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[N:%.*]] = and i16 [[NN:%.*]], 123
+; CHECK-NEXT:    [[X:%.*]] = or i16 [[XX:%.*]], 1
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    call void @maythrow()
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i16 [[N]], [[X]]
+; CHECK-NEXT:    call void @use(i16 [[DIV]])
+; CHECK-NEXT:    br label [[LOOP]]
+;
+entry:
+  %n = and i16 %nn, 123
+  %x = or i16 %xx, 1
+  br label %loop
+loop:
+  call void @maythrow()
+  %div = sdiv i16 %n, %x
+  call void @use(i16 %div)
+  br label %loop
+}
+
+define void @udiv_not_ok(i16 %n, i16 noundef %xx) {
 ; CHECK-LABEL: @udiv_not_ok(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[X:%.*]] = xor i16 [[XX:%.*]], 1
@@ -113,10 +159,31 @@ loop:
   br label %loop
 }
 
-define void @udiv_ok(i16 %n, i16 %xx) {
+define void @udiv_ok(i16 %n, i16 noundef %xx) {
 ; CHECK-LABEL: @udiv_ok(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[X:%.*]] = or i16 [[XX:%.*]], 1
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i16 [[N:%.*]], [[X]]
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    call void @maythrow()
+; CHECK-NEXT:    call void @use(i16 [[DIV]])
+; CHECK-NEXT:    br label [[LOOP]]
+;
+entry:
+  %x = or i16 %xx, 1
+  br label %loop
+loop:
+  call void @maythrow()
+  %div = udiv i16 %n, %x
+  call void @use(i16 %div)
+  br label %loop
+}
+
+define void @urem_not_ok_maybe_poison(i16 %n, i16 %xx) {
+; CHECK-LABEL: @urem_not_ok_maybe_poison(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[X:%.*]] = or i16 [[XX:%.*]], 1
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    call void @maythrow()


        


More information about the llvm-commits mailing list