[InstCombine] do not add "nuw" to 1<<X if the "1" has undefined elements
authorSanjay Patel <spatel@rotateright.com>
Mon, 26 Dec 2022 18:12:44 +0000 (13:12 -0500)
committerSanjay Patel <spatel@rotateright.com>
Mon, 26 Dec 2022 18:16:03 +0000 (13:16 -0500)
This was noted as a potential miscompile in the post-commit feedback
for the patch that added this fold:
d4493dd1ed58ac3f1eab0

llvm/include/llvm/IR/Constant.h
llvm/lib/IR/Constants.cpp
llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
llvm/test/Transforms/InstCombine/icmp-uge-of-add-of-shl-one-by-bits-to-allones-and-val-to-icmp-eq-of-lshr-val-by-bits-and-0.ll
llvm/test/Transforms/InstCombine/icmp-ult-of-add-of-shl-one-by-bits-to-allones-and-val-to-icmp-ne-of-lshr-val-by-bits-and-0.ll

index 09fb2c9..7787640 100644 (file)
@@ -111,6 +111,10 @@ public:
   /// elements.
   bool containsPoisonElement() const;
 
+  /// Return true if this is a vector constant that includes any strictly undef
+  /// (not poison) elements.
+  bool containsUndefElement() const;
+
   /// Return true if this is a fixed width vector constant that includes
   /// any constant expressions.
   bool containsConstantExpression() const;
index 9c8e299..a6c4c8b 100644 (file)
@@ -337,6 +337,12 @@ bool Constant::containsPoisonElement() const {
       this, [&](const auto *C) { return isa<PoisonValue>(C); });
 }
 
+bool Constant::containsUndefElement() const {
+  return containsUndefinedElement(this, [&](const auto *C) {
+    return isa<UndefValue>(C) && !isa<PoisonValue>(C);
+  });
+}
+
 bool Constant::containsConstantExpression() const {
   if (auto *VTy = dyn_cast<FixedVectorType>(getType())) {
     for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
index d4a6e9d..1fce517 100644 (file)
@@ -1065,9 +1065,11 @@ Instruction *InstCombinerImpl::visitShl(BinaryOperator &I) {
       return BinaryOperator::CreateLShr(
           ConstantInt::get(Ty, APInt::getSignMask(BitWidth)), X);
 
-    // The only way to shift out the 1 is with an over-shift, and that would
-    // be poison either way.
-    if (!I.hasNoUnsignedWrap()) {
+    // The only way to shift out the 1 is with an over-shift, so that would
+    // be poison with or without "nuw". Undef is excluded because (undef << X)
+    // is not undef (it is zero).
+    Constant *ConstantOne = cast<Constant>(Op0);
+    if (!I.hasNoUnsignedWrap() && !ConstantOne->containsUndefElement()) {
       I.setHasNoUnsignedWrap();
       return &I;
     }
index 2426d8c..b33ba41 100644 (file)
@@ -54,7 +54,7 @@ define <2 x i1> @p1_vec(<2 x i8> %val, <2 x i8> %bits) {
 
 define <3 x i1> @p2_vec_undef0(<3 x i8> %val, <3 x i8> %bits) {
 ; CHECK-LABEL: @p2_vec_undef0(
-; CHECK-NEXT:    [[T0:%.*]] = shl nuw <3 x i8> <i8 1, i8 undef, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    [[T0:%.*]] = shl <3 x i8> <i8 1, i8 undef, i8 1>, [[BITS:%.*]]
 ; CHECK-NEXT:    call void @use3i8(<3 x i8> [[T0]])
 ; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]]
 ; CHECK-NEXT:    [[R:%.*]] = icmp eq <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
index bcfc898..1c46e77 100644 (file)
@@ -54,7 +54,7 @@ define <2 x i1> @p1_vec(<2 x i8> %val, <2 x i8> %bits) {
 
 define <3 x i1> @p2_vec_undef0(<3 x i8> %val, <3 x i8> %bits) {
 ; CHECK-LABEL: @p2_vec_undef0(
-; CHECK-NEXT:    [[T0:%.*]] = shl nuw <3 x i8> <i8 1, i8 undef, i8 1>, [[BITS:%.*]]
+; CHECK-NEXT:    [[T0:%.*]] = shl <3 x i8> <i8 1, i8 undef, i8 1>, [[BITS:%.*]]
 ; CHECK-NEXT:    call void @use3i8(<3 x i8> [[T0]])
 ; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]]
 ; CHECK-NEXT:    [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer