[llvm] [LICM] Preserve Disjoint flag on OR when hoisting. (PR #140266)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Sat May 17 02:59:09 PDT 2025


https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/140266

>From d88c6d87d8fde923d83dcbb99632500f715e84cd Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 16 May 2025 15:59:15 +0100
Subject: [PATCH 1/3] [LICM] Add tests for hoisting OR disjoint.

---
 llvm/test/Transforms/LICM/hoist-binop.ll | 63 ++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/llvm/test/Transforms/LICM/hoist-binop.ll b/llvm/test/Transforms/LICM/hoist-binop.ll
index ea7d96c07d5ff..289e0f87d4d8c 100644
--- a/llvm/test/Transforms/LICM/hoist-binop.ll
+++ b/llvm/test/Transforms/LICM/hoist-binop.ll
@@ -723,6 +723,69 @@ loop:
   br label %loop
 }
 
+; Trivially hoist or disjoint.
+define void @or_all_disjoint(i64 %c1, i64 %c2) {
+; CHECK-LABEL: @or_all_disjoint(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[INVARIANT_OP:%.*]] = or i64 [[C1:%.*]], [[C2:%.*]]
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[INDEX_NEXT_REASS]] = or i64 [[INDEX]], [[INVARIANT_OP]]
+; CHECK-NEXT:    br label [[LOOP]]
+;
+entry:
+  br label %loop
+
+loop:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %loop ]
+  %step.add = or disjoint i64 %index, %c1
+  %index.next = or disjoint i64 %c2, %step.add
+  br label %loop
+}
+
+; Trivially hoist or, disjoint on first or only .
+define void @or_disjoint_on_first_or_only(i64 %c1, i64 %c2) {
+; CHECK-LABEL: @or_disjoint_on_first_or_only(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[INVARIANT_OP:%.*]] = or i64 [[C1:%.*]], [[C2:%.*]]
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[INDEX_NEXT_REASS]] = or i64 [[INDEX]], [[INVARIANT_OP]]
+; CHECK-NEXT:    br label [[LOOP]]
+;
+entry:
+  br label %loop
+
+loop:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %loop ]
+  %step.add = or i64 %index, %c1
+  %index.next = or disjoint i64 %c2, %step.add
+  br label %loop
+}
+
+; Trivially hoist or, disjoint on second or only .
+define void @or_disjoint_on_second_or_only(i64 %c1, i64 %c2) {
+; CHECK-LABEL: @or_disjoint_on_second_or_only(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[INVARIANT_OP:%.*]] = or i64 [[C1:%.*]], [[C2:%.*]]
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[INDEX_NEXT_REASS]] = or i64 [[INDEX]], [[INVARIANT_OP]]
+; CHECK-NEXT:    br label [[LOOP]]
+;
+entry:
+  br label %loop
+
+loop:
+  %index = phi i64 [ 0, %entry ], [ %index.next, %loop ]
+  %step.add = or disjoint i64 %index, %c1
+  %index.next = or i64 %c2, %step.add
+  br label %loop
+}
+
 ; Trivially hoist xor.
 define void @xor(i64 %c1, i64 %c2) {
 ; CHECK-LABEL: @xor(

>From b305b7ef897697ef8196cbb7681c01691db1d794 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 16 May 2025 16:00:34 +0100
Subject: [PATCH 2/3] [LICM] Preserve Disjoint flag on OR when hoisting.

Update hoistBOAssociation to preserve Disjoint flags on the newly
created instructions if both ORs are disjoint.

Fixes https://github.com/llvm/llvm-project/issues/139625.
---
 llvm/lib/Transforms/Scalar/LICM.cpp      | 6 ++++++
 llvm/test/Transforms/LICM/hoist-binop.ll | 4 ++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index 62ef40c686874..cbdb8bf661a23 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -2877,6 +2877,12 @@ static bool hoistBOAssociation(Instruction &I, Loop &L,
     if (auto *I = dyn_cast<Instruction>(Inv))
       I->setFastMathFlags(Intersect);
     NewBO->setFastMathFlags(Intersect);
+  } else if (Opcode == Instruction::Or) {
+    bool Disjoint = cast<PossiblyDisjointInst>(BO)->isDisjoint() &&
+                    cast<PossiblyDisjointInst>(BO0)->isDisjoint();
+    if (auto *I = dyn_cast<PossiblyDisjointInst>(Inv))
+      I->setIsDisjoint(Disjoint);
+    cast<PossiblyDisjointInst>(NewBO)->setIsDisjoint(Disjoint);
   }
 
   BO->replaceAllUsesWith(NewBO);
diff --git a/llvm/test/Transforms/LICM/hoist-binop.ll b/llvm/test/Transforms/LICM/hoist-binop.ll
index 289e0f87d4d8c..000b1fc1c5ce6 100644
--- a/llvm/test/Transforms/LICM/hoist-binop.ll
+++ b/llvm/test/Transforms/LICM/hoist-binop.ll
@@ -727,11 +727,11 @@ loop:
 define void @or_all_disjoint(i64 %c1, i64 %c2) {
 ; CHECK-LABEL: @or_all_disjoint(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[INVARIANT_OP:%.*]] = or i64 [[C1:%.*]], [[C2:%.*]]
+; CHECK-NEXT:    [[INVARIANT_OP:%.*]] = or disjoint i64 [[C1:%.*]], [[C2:%.*]]
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ]
-; CHECK-NEXT:    [[INDEX_NEXT_REASS]] = or i64 [[INDEX]], [[INVARIANT_OP]]
+; CHECK-NEXT:    [[INDEX_NEXT_REASS]] = or disjoint i64 [[INDEX]], [[INVARIANT_OP]]
 ; CHECK-NEXT:    br label [[LOOP]]
 ;
 entry:

>From 44e9e4e856d9c73d4ee18cfc540b39c6acafb778 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sat, 17 May 2025 10:58:44 +0100
Subject: [PATCH 3/3] !fixup add comment regarding folding.

---
 llvm/lib/Transforms/Scalar/LICM.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index cbdb8bf661a23..7d89a13fa3bab 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -2880,6 +2880,7 @@ static bool hoistBOAssociation(Instruction &I, Loop &L,
   } else if (Opcode == Instruction::Or) {
     bool Disjoint = cast<PossiblyDisjointInst>(BO)->isDisjoint() &&
                     cast<PossiblyDisjointInst>(BO0)->isDisjoint();
+    // If `Inv` was not constant-folded, a new Instruction has been created.
     if (auto *I = dyn_cast<PossiblyDisjointInst>(Inv))
       I->setIsDisjoint(Disjoint);
     cast<PossiblyDisjointInst>(NewBO)->setIsDisjoint(Disjoint);



More information about the llvm-commits mailing list