[llvm] cd31cf5 - [InstSimplify] Fix or disjoint miscompile with op replacement

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 1 02:45:20 PST 2023


Author: Nikita Popov
Date: 2023-12-01T11:45:09+01:00
New Revision: cd31cf5989aaf6a187aaf3af4f94207c55a70d0f

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

LOG: [InstSimplify] Fix or disjoint miscompile with op replacement

Make sure %x does not get folded to "or disjoint %x, %x" without
dropping the flag, as this would be a derefinement.

Added: 
    

Modified: 
    llvm/lib/Analysis/InstructionSimplify.cpp
    llvm/test/Transforms/InstCombine/select.ll
    llvm/test/Transforms/InstSimplify/select.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 9f3b3f25ec3f154..cef9f6ec179ba59 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -4331,8 +4331,17 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
 
       // x & x -> x, x | x -> x
       if ((Opcode == Instruction::And || Opcode == Instruction::Or) &&
-          NewOps[0] == NewOps[1])
+          NewOps[0] == NewOps[1]) {
+        // or disjoint x, x results in poison.
+        if (auto *PDI = dyn_cast<PossiblyDisjointInst>(BO)) {
+          if (PDI->isDisjoint()) {
+            if (!DropFlags)
+              return nullptr;
+            DropFlags->push_back(BO);
+          }
+        }
         return NewOps[0];
+      }
 
       // x - x -> 0, x ^ x -> 0. This is non-refining, because x is non-poison
       // by assumption and this case never wraps, so nowrap flags can be

diff  --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index f1ccd4747bd1ce1..6f24758effac2fa 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -2916,10 +2916,9 @@ define i8 @replace_false_op_eq_shl_or_disjoint(i8 %x) {
   ret i8 %sel
 }
 
-; FIXME: This is a miscompile.
 define i8 @select_or_disjoint_eq(i8 %x, i8 %y) {
 ; CHECK-LABEL: @select_or_disjoint_eq(
-; CHECK-NEXT:    [[OR:%.*]] = or disjoint i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    ret i8 [[OR]]
 ;
   %cmp = icmp eq i8 %x, %y

diff  --git a/llvm/test/Transforms/InstSimplify/select.ll b/llvm/test/Transforms/InstSimplify/select.ll
index 473d8b8b0368084..b9c79f02245ccff 100644
--- a/llvm/test/Transforms/InstSimplify/select.ll
+++ b/llvm/test/Transforms/InstSimplify/select.ll
@@ -1725,11 +1725,12 @@ define i8 @select_or_eq(i8 %x, i8 %y) {
   ret i8 %sel
 }
 
-; FIXME: This is a miscompile.
 define i8 @select_or_disjoint_eq(i8 %x, i8 %y) {
 ; CHECK-LABEL: @select_or_disjoint_eq(
-; CHECK-NEXT:    [[OR:%.*]] = or disjoint i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    ret i8 [[OR]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or disjoint i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i8 [[X]], i8 [[OR]]
+; CHECK-NEXT:    ret i8 [[SEL]]
 ;
   %cmp = icmp eq i8 %x, %y
   %or = or disjoint i8 %x, %y


        


More information about the llvm-commits mailing list