[llvm] [ConstraintElim] Use disjoint flag for decomposition (PR #74478)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 5 06:33:36 PST 2023


https://github.com/nikic created https://github.com/llvm/llvm-project/pull/74478

Use the or disjoint flag for decomposing or into add, which will handle cases that haveNoCommonBitsSet() may not be able to reinfer (e.g. because they require context-sensitive facts, which the call here does not use.)

>From 3a6a3267fc614e7a60c0370cbccdc4d04f0494c7 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 5 Dec 2023 15:30:59 +0100
Subject: [PATCH] [ConstraintElim] Use disjoint flag for decomposition

Use the or disjoint flag for decomposing or into add, which will
handle cases that haveNoCommonBitsSet() may not be able to reinfer
(e.g. because they require context-sensitive facts, which the call
here does not use.)
---
 .../Scalar/ConstraintElimination.cpp          |   4 +-
 .../Transforms/ConstraintElimination/or.ll    | 145 +++++++++++++-----
 2 files changed, 106 insertions(+), 43 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 898f29f4b9ecc..a6fbddca5cba4 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -544,10 +544,8 @@ static Decomposition decompose(Value *V,
   }
 
   // Decompose or as an add if there are no common bits between the operands.
-  if (match(V, m_Or(m_Value(Op0), m_ConstantInt(CI))) &&
-      haveNoCommonBitsSet(Op0, CI, DL)) {
+  if (match(V, m_DisjointOr(m_Value(Op0), m_ConstantInt(CI))))
     return MergeResults(Op0, CI, IsSigned);
-  }
 
   if (match(V, m_NUWShl(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI)) {
     if (CI->getSExtValue() < 0 || CI->getSExtValue() >= 64)
diff --git a/llvm/test/Transforms/ConstraintElimination/or.ll b/llvm/test/Transforms/ConstraintElimination/or.ll
index 4f46f546bd32f..2f24519ddd1d5 100644
--- a/llvm/test/Transforms/ConstraintElimination/or.ll
+++ b/llvm/test/Transforms/ConstraintElimination/or.ll
@@ -414,20 +414,20 @@ define void @test_or_as_add_ult(i8 %init_val, i8 %high) {
 ; CHECK:       then:
 ; CHECK-NEXT:    [[F_0:%.*]] = icmp ult i8 [[START]], [[HIGH]]
 ; CHECK-NEXT:    call void @use(i1 [[F_0]])
-; CHECK-NEXT:    [[I_1:%.*]] = or i8 [[START]], 1
+; CHECK-NEXT:    [[I_1:%.*]] = or disjoint i8 [[START]], 1
 ; CHECK-NEXT:    [[F_1:%.*]] = icmp ult i8 [[I_1]], [[HIGH]]
 ; CHECK-NEXT:    call void @use(i1 [[F_1]])
-; CHECK-NEXT:    [[I_2:%.*]] = or i8 [[START]], 2
+; CHECK-NEXT:    [[I_2:%.*]] = or disjoint i8 [[START]], 2
 ; CHECK-NEXT:    [[F_2:%.*]] = icmp ult i8 [[I_2]], [[HIGH]]
 ; CHECK-NEXT:    call void @use(i1 [[F_2]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       end:
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    [[START_1:%.*]] = or i8 [[START]], 1
+; CHECK-NEXT:    [[START_1:%.*]] = or disjoint i8 [[START]], 1
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    [[START_2:%.*]] = or i8 [[START]], 2
+; CHECK-NEXT:    [[START_2:%.*]] = or disjoint i8 [[START]], 2
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    [[START_3:%.*]] = or i8 [[START]], 3
+; CHECK-NEXT:    [[START_3:%.*]] = or disjoint i8 [[START]], 3
 ; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[START_4:%.*]] = or i8 [[START]], 4
 ; CHECK-NEXT:    [[C_4:%.*]] = icmp ult i8 [[START_4]], [[HIGH]]
@@ -443,10 +443,10 @@ entry:
 then:                                          ; preds = %entry
   %f.0 = icmp ult i8 %start, %high
   call void @use(i1 %f.0)
-  %i.1 = or i8 %start, 1
+  %i.1 = or disjoint i8 %start, 1
   %f.1 = icmp ult i8 %i.1, %high
   call void @use(i1 %f.1)
-  %i.2 = or i8 %start, 2
+  %i.2 = or disjoint i8 %start, 2
   %f.2 = icmp ult i8 %i.2, %high
   call void @use(i1 %f.2)
   ret void
@@ -454,13 +454,13 @@ then:                                          ; preds = %entry
 end:                                           ; preds = %entry
   %t.0 = icmp ult i8 %start, %high
   call void @use(i1 %t.0)
-  %start.1 = or i8 %start, 1
+  %start.1 = or disjoint i8 %start, 1
   %t.1 = icmp ult i8 %start.1, %high
   call void @use(i1 %t.1)
-  %start.2 = or i8 %start, 2
+  %start.2 = or disjoint i8 %start, 2
   %t.2 = icmp ult i8 %start.2, %high
   call void @use(i1 %t.2)
-  %start.3 = or i8 %start, 3
+  %start.3 = or disjoint i8 %start, 3
   %t.3 = icmp ult i8 %start.3, %high
   call void @use(i1 %t.3)
   %start.4 = or i8 %start, 4
@@ -479,20 +479,20 @@ define void @test_or_as_add_ule(i8 %init_val, i8 %high) {
 ; CHECK:       then:
 ; CHECK-NEXT:    [[F_0:%.*]] = icmp ule i8 [[START]], [[HIGH]]
 ; CHECK-NEXT:    call void @use(i1 [[F_0]])
-; CHECK-NEXT:    [[I_1:%.*]] = or i8 [[START]], 1
+; CHECK-NEXT:    [[I_1:%.*]] = or disjoint i8 [[START]], 1
 ; CHECK-NEXT:    [[F_1:%.*]] = icmp ule i8 [[I_1]], [[HIGH]]
 ; CHECK-NEXT:    call void @use(i1 [[F_1]])
-; CHECK-NEXT:    [[I_2:%.*]] = or i8 [[START]], 2
+; CHECK-NEXT:    [[I_2:%.*]] = or disjoint i8 [[START]], 2
 ; CHECK-NEXT:    [[F_2:%.*]] = icmp ule i8 [[I_2]], [[HIGH]]
 ; CHECK-NEXT:    call void @use(i1 [[F_2]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       end:
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    [[START_1:%.*]] = or i8 [[START]], 1
+; CHECK-NEXT:    [[START_1:%.*]] = or disjoint i8 [[START]], 1
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    [[START_2:%.*]] = or i8 [[START]], 2
+; CHECK-NEXT:    [[START_2:%.*]] = or disjoint i8 [[START]], 2
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    [[START_3:%.*]] = or i8 [[START]], 3
+; CHECK-NEXT:    [[START_3:%.*]] = or disjoint i8 [[START]], 3
 ; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[START_4:%.*]] = or i8 [[START]], 4
 ; CHECK-NEXT:    [[T_4:%.*]] = icmp ule i8 [[START_4]], [[HIGH]]
@@ -511,10 +511,10 @@ entry:
 then:                                          ; preds = %entry
   %f.0 = icmp ule i8 %start, %high
   call void @use(i1 %f.0)
-  %i.1 = or i8 %start, 1
+  %i.1 = or disjoint i8 %start, 1
   %f.1 = icmp ule i8 %i.1, %high
   call void @use(i1 %f.1)
-  %i.2 = or i8 %start, 2
+  %i.2 = or disjoint i8 %start, 2
   %f.2 = icmp ule i8 %i.2, %high
   call void @use(i1 %f.2)
   ret void
@@ -522,13 +522,13 @@ then:                                          ; preds = %entry
 end:                                           ; preds = %entry
   %t.0 = icmp ule i8 %start, %high
   call void @use(i1 %t.0)
-  %start.1 = or i8 %start, 1
+  %start.1 = or disjoint i8 %start, 1
   %t.1 = icmp ule i8 %start.1, %high
   call void @use(i1 %t.1)
-  %start.2 = or i8 %start, 2
+  %start.2 = or disjoint i8 %start, 2
   %t.2 = icmp ule i8 %start.2, %high
   call void @use(i1 %t.2)
-  %start.3 = or i8 %start, 3
+  %start.3 = or disjoint i8 %start, 3
   %t.3 = icmp ule i8 %start.3, %high
   call void @use(i1 %t.3)
   %start.4 = or i8 %start, 4
@@ -551,20 +551,20 @@ define void @test_or_as_add_ugt(i8 %init_val, i8 %high) {
 ; CHECK:       then:
 ; CHECK-NEXT:    [[T_0:%.*]] = icmp ugt i8 [[START]], [[HIGH]]
 ; CHECK-NEXT:    call void @use(i1 [[T_0]])
-; CHECK-NEXT:    [[I_1:%.*]] = or i8 [[START]], 1
+; CHECK-NEXT:    [[I_1:%.*]] = or disjoint i8 [[START]], 1
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ugt i8 [[I_1]], [[HIGH]]
 ; CHECK-NEXT:    call void @use(i1 [[T_1]])
-; CHECK-NEXT:    [[I_2:%.*]] = or i8 [[START]], 2
+; CHECK-NEXT:    [[I_2:%.*]] = or disjoint i8 [[START]], 2
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ugt i8 [[I_2]], [[HIGH]]
 ; CHECK-NEXT:    call void @use(i1 [[T_2]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       end:
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[START_1:%.*]] = or i8 [[START]], 1
+; CHECK-NEXT:    [[START_1:%.*]] = or disjoint i8 [[START]], 1
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[START_2:%.*]] = or i8 [[START]], 2
+; CHECK-NEXT:    [[START_2:%.*]] = or disjoint i8 [[START]], 2
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[START_3:%.*]] = or i8 [[START]], 3
+; CHECK-NEXT:    [[START_3:%.*]] = or disjoint i8 [[START]], 3
 ; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    [[START_4:%.*]] = or i8 [[START]], 4
 ; CHECK-NEXT:    [[F_4:%.*]] = icmp ugt i8 [[START_4]], [[HIGH]]
@@ -583,10 +583,10 @@ entry:
 then:                                          ; preds = %entry
   %t.0 = icmp ugt i8 %start, %high
   call void @use(i1 %t.0)
-  %i.1 = or i8 %start, 1
+  %i.1 = or disjoint i8 %start, 1
   %t.1 = icmp ugt i8 %i.1, %high
   call void @use(i1 %t.1)
-  %i.2 = or i8 %start, 2
+  %i.2 = or disjoint i8 %start, 2
   %t.2 = icmp ugt i8 %i.2, %high
   call void @use(i1 %t.2)
   ret void
@@ -594,13 +594,13 @@ then:                                          ; preds = %entry
 end:                                           ; preds = %entry
   %f.0 = icmp ugt i8 %start, %high
   call void @use(i1 %f.0)
-  %start.1 = or i8 %start, 1
+  %start.1 = or disjoint i8 %start, 1
   %f.1 = icmp ugt i8 %start.1, %high
   call void @use(i1 %f.1)
-  %start.2 = or i8 %start, 2
+  %start.2 = or disjoint i8 %start, 2
   %f.2 = icmp ugt i8 %start.2, %high
   call void @use(i1 %f.2)
-  %start.3 = or i8 %start, 3
+  %start.3 = or disjoint i8 %start, 3
   %f.3 = icmp ugt i8 %start.3, %high
   call void @use(i1 %f.3)
   %start.4 = or i8 %start, 4
@@ -622,20 +622,20 @@ define void @test_or_as_add_uge(i8 %init_val, i8 %high) {
 ; CHECK:       then:
 ; CHECK-NEXT:    [[T_0:%.*]] = icmp ugt i8 [[START]], [[HIGH]]
 ; CHECK-NEXT:    call void @use(i1 [[T_0]])
-; CHECK-NEXT:    [[I_1:%.*]] = or i8 [[START]], 1
+; CHECK-NEXT:    [[I_1:%.*]] = or disjoint i8 [[START]], 1
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i8 [[I_1]], [[HIGH]]
 ; CHECK-NEXT:    call void @use(i1 [[T_1]])
-; CHECK-NEXT:    [[I_2:%.*]] = or i8 [[START]], 2
+; CHECK-NEXT:    [[I_2:%.*]] = or disjoint i8 [[START]], 2
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp uge i8 [[I_2]], [[HIGH]]
 ; CHECK-NEXT:    call void @use(i1 [[T_2]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       end:
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[START_1:%.*]] = or i8 [[START]], 1
+; CHECK-NEXT:    [[START_1:%.*]] = or disjoint i8 [[START]], 1
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[START_2:%.*]] = or i8 [[START]], 2
+; CHECK-NEXT:    [[START_2:%.*]] = or disjoint i8 [[START]], 2
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[START_3:%.*]] = or i8 [[START]], 3
+; CHECK-NEXT:    [[START_3:%.*]] = or disjoint i8 [[START]], 3
 ; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    [[START_4:%.*]] = or i8 [[START]], 4
 ; CHECK-NEXT:    [[C_4:%.*]] = icmp uge i8 [[START_4]], [[HIGH]]
@@ -654,10 +654,10 @@ entry:
 then:                                          ; preds = %entry
   %t.0 = icmp ugt i8 %start, %high
   call void @use(i1 %t.0)
-  %i.1 = or i8 %start, 1
+  %i.1 = or disjoint i8 %start, 1
   %t.1 = icmp uge i8 %i.1, %high
   call void @use(i1 %t.1)
-  %i.2 = or i8 %start, 2
+  %i.2 = or disjoint i8 %start, 2
   %t.2 = icmp uge i8 %i.2, %high
   call void @use(i1 %t.2)
   ret void
@@ -665,13 +665,13 @@ then:                                          ; preds = %entry
 end:                                           ; preds = %entry
   %f.0 = icmp ugt i8 %start, %high
   call void @use(i1 %f.0)
-  %start.1 = or i8 %start, 1
+  %start.1 = or disjoint i8 %start, 1
   %f.1 = icmp uge i8 %start.1, %high
   call void @use(i1 %f.1)
-  %start.2 = or i8 %start, 2
+  %start.2 = or disjoint i8 %start, 2
   %f.2 = icmp uge i8 %start.2, %high
   call void @use(i1 %f.2)
-  %start.3 = or i8 %start, 3
+  %start.3 = or disjoint i8 %start, 3
   %f.3 = icmp uge i8 %start.3, %high
   call void @use(i1 %f.3)
   %start.4 = or i8 %start, 4
@@ -748,3 +748,68 @@ end:                                           ; preds = %entry
 
   ret void
 }
+
+; Nothing in the IR implies the disjoint flag, but we can still use it
+; to decompose into an add.
+define void @test_decompose_explicit_disjoint(i8 %start, i8 %high) {
+; CHECK-LABEL: @test_decompose_explicit_disjoint(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[START_PLUS_3:%.*]] = add nuw i8 [[START:%.*]], 3
+; CHECK-NEXT:    [[C_1:%.*]] = icmp uge i8 [[START_PLUS_3]], [[HIGH:%.*]]
+; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[END:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[I_1:%.*]] = or disjoint i8 [[START]], 1
+; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i8 [[I_1]], [[HIGH]]
+; CHECK-NEXT:    call void @use(i1 [[T_1]])
+; CHECK-NEXT:    [[I_2:%.*]] = or disjoint i8 [[START]], 2
+; CHECK-NEXT:    [[T_2:%.*]] = icmp uge i8 [[I_2]], [[HIGH]]
+; CHECK-NEXT:    call void @use(i1 [[T_2]])
+; CHECK-NEXT:    ret void
+; CHECK:       end:
+; CHECK-NEXT:    [[START_1:%.*]] = or disjoint i8 [[START]], 1
+; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    [[START_2:%.*]] = or disjoint i8 [[START]], 2
+; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    [[START_3:%.*]] = or disjoint i8 [[START]], 3
+; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    [[START_4:%.*]] = or disjoint i8 [[START]], 4
+; CHECK-NEXT:    [[C_4:%.*]] = icmp uge i8 [[START_4]], [[HIGH]]
+; CHECK-NEXT:    call void @use(i1 [[C_4]])
+; CHECK-NEXT:    [[START_5:%.*]] = or disjoint i8 [[START]], 5
+; CHECK-NEXT:    [[C_5:%.*]] = icmp uge i8 [[START_5]], [[HIGH]]
+; CHECK-NEXT:    call void @use(i1 [[C_5]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %start.plus.3 = add nuw i8 %start, 3
+  %c.1 = icmp uge i8 %start.plus.3, %high
+  br i1 %c.1, label %then, label %end
+
+then:                                          ; preds = %entry
+  %i.1 = or disjoint i8 %start, 1
+  %t.1 = icmp uge i8 %i.1, %high
+  call void @use(i1 %t.1)
+  %i.2 = or disjoint i8 %start, 2
+  %t.2 = icmp uge i8 %i.2, %high
+  call void @use(i1 %t.2)
+  ret void
+
+end:                                           ; preds = %entry
+  %start.1 = or disjoint i8 %start, 1
+  %f.1 = icmp uge i8 %start.1, %high
+  call void @use(i1 %f.1)
+  %start.2 = or disjoint i8 %start, 2
+  %f.2 = icmp uge i8 %start.2, %high
+  call void @use(i1 %f.2)
+  %start.3 = or disjoint i8 %start, 3
+  %f.3 = icmp uge i8 %start.3, %high
+  call void @use(i1 %f.3)
+  %start.4 = or disjoint i8 %start, 4
+  %c.4 = icmp uge i8 %start.4, %high
+  call void @use(i1 %c.4)
+  %start.5 = or disjoint i8 %start, 5
+  %c.5 = icmp uge i8 %start.5, %high
+  call void @use(i1 %c.5)
+
+  ret void
+}



More information about the llvm-commits mailing list