[llvm-branch-commits] [llvm] c6b62ef - [ConstantFold] Fold operations to poison if possible

Juneyoung Lee via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat Nov 28 09:33:26 PST 2020


Author: Juneyoung Lee
Date: 2020-11-29T02:28:40+09:00
New Revision: c6b62efb9103466b6cefca1bd99a5b04b4ced044

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

LOG: [ConstantFold] Fold operations to poison if possible

This patch updates ConstantFold, so operations are folded into poison if possible.

<alive2 proofs>
casts: https://alive2.llvm.org/ce/z/WSj7rw
binary operations (arithmetic): https://alive2.llvm.org/ce/z/_7dEyJ
binary operations (bitwise): https://alive2.llvm.org/ce/z/cezjVN
vector/aggregate operations: https://alive2.llvm.org/ce/z/BQ7hWz
unary ops: https://alive2.llvm.org/ce/z/yBRs4q
other ops: https://alive2.llvm.org/ce/z/iXbcFD

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D92203

Added: 
    llvm/test/Transforms/InstSimplify/ConstProp/poison.ll

Modified: 
    llvm/lib/IR/ConstantFold.cpp
    llvm/lib/IR/Constants.cpp
    llvm/test/Transforms/InstSimplify/ConstProp/InsertElement.ll
    llvm/unittests/IR/ConstantsTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp
index b8502673a829..a52cd725d530 100644
--- a/llvm/lib/IR/ConstantFold.cpp
+++ b/llvm/lib/IR/ConstantFold.cpp
@@ -522,6 +522,9 @@ static Constant *getFoldedOffsetOf(Type *Ty, Constant *FieldNo, Type *DestTy,
 
 Constant *llvm::ConstantFoldCastInstruction(unsigned opc, Constant *V,
                                             Type *DestTy) {
+  if (isa<PoisonValue>(V))
+    return PoisonValue::get(DestTy);
+
   if (isa<UndefValue>(V)) {
     // zext(undef) = 0, because the top bits will be zero.
     // sext(undef) = 0, because the top bits will all be the same.
@@ -759,7 +762,9 @@ Constant *llvm::ConstantFoldSelectInstruction(Constant *Cond,
       Constant *V2Element = ConstantExpr::getExtractElement(V2,
                                                     ConstantInt::get(Ty, i));
       auto *Cond = cast<Constant>(CondV->getOperand(i));
-      if (V1Element == V2Element) {
+      if (isa<PoisonValue>(Cond)) {
+        V = PoisonValue::get(V1Element->getType());
+      } else if (V1Element == V2Element) {
         V = V1Element;
       } else if (isa<UndefValue>(Cond)) {
         V = isa<UndefValue>(V1Element) ? V1Element : V2Element;
@@ -775,6 +780,9 @@ Constant *llvm::ConstantFoldSelectInstruction(Constant *Cond,
       return ConstantVector::get(Result);
   }
 
+  if (isa<PoisonValue>(Cond))
+    return PoisonValue::get(V1->getType());
+
   if (isa<UndefValue>(Cond)) {
     if (isa<UndefValue>(V1)) return V1;
     return V2;
@@ -782,9 +790,17 @@ Constant *llvm::ConstantFoldSelectInstruction(Constant *Cond,
 
   if (V1 == V2) return V1;
 
+  if (isa<PoisonValue>(V1))
+    return V2;
+  if (isa<PoisonValue>(V2))
+    return V1;
+
   // If the true or false value is undef, we can fold to the other value as
   // long as the other value isn't poison.
   auto NotPoison = [](Constant *C) {
+    if (isa<PoisonValue>(C))
+      return false;
+
     // TODO: We can analyze ConstExpr by opcode to determine if there is any
     //       possibility of poison.
     if (isa<ConstantExpr>(C))
@@ -821,9 +837,13 @@ Constant *llvm::ConstantFoldExtractElementInstruction(Constant *Val,
                                                       Constant *Idx) {
   auto *ValVTy = cast<VectorType>(Val->getType());
 
+  // extractelt poison, C -> poison
+  // extractelt C, undef -> poison
+  if (isa<PoisonValue>(Val) || isa<UndefValue>(Idx))
+    return PoisonValue::get(ValVTy->getElementType());
+
   // extractelt undef, C -> undef
-  // extractelt C, undef -> undef
-  if (isa<UndefValue>(Val) || isa<UndefValue>(Idx))
+  if (isa<UndefValue>(Val))
     return UndefValue::get(ValVTy->getElementType());
 
   auto *CIdx = dyn_cast<ConstantInt>(Idx);
@@ -831,9 +851,9 @@ Constant *llvm::ConstantFoldExtractElementInstruction(Constant *Val,
     return nullptr;
 
   if (auto *ValFVTy = dyn_cast<FixedVectorType>(Val->getType())) {
-    // ee({w,x,y,z}, wrong_value) -> undef
+    // ee({w,x,y,z}, wrong_value) -> poison
     if (CIdx->uge(ValFVTy->getNumElements()))
-      return UndefValue::get(ValFVTy->getElementType());
+      return PoisonValue::get(ValFVTy->getElementType());
   }
 
   // ee (gep (ptr, idx0, ...), idx) -> gep (ee (ptr, idx), ee (idx0, idx), ...)
@@ -882,7 +902,7 @@ Constant *llvm::ConstantFoldInsertElementInstruction(Constant *Val,
                                                      Constant *Elt,
                                                      Constant *Idx) {
   if (isa<UndefValue>(Idx))
-    return UndefValue::get(Val->getType());
+    return PoisonValue::get(Val->getType());
 
   ConstantInt *CIdx = dyn_cast<ConstantInt>(Idx);
   if (!CIdx) return nullptr;
@@ -1084,6 +1104,10 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1,
       return C1;
   }
 
+  // Binary operations propagate poison.
+  if (isa<PoisonValue>(C1) || isa<PoisonValue>(C2))
+    return PoisonValue::get(C1->getType());
+
   // Handle scalar UndefValue and scalable vector UndefValue. Fixed-length
   // vectors are always evaluated per element.
   bool IsScalableVector = isa<ScalableVectorType>(C1->getType());
@@ -1922,6 +1946,9 @@ Constant *llvm::ConstantFoldCompareInstruction(unsigned short pred,
     return Constant::getAllOnesValue(ResultTy);
 
   // Handle some degenerate cases first
+  if (isa<PoisonValue>(C1) || isa<PoisonValue>(C2))
+    return PoisonValue::get(ResultTy);
+
   if (isa<UndefValue>(C1) || isa<UndefValue>(C2)) {
     CmpInst::Predicate Predicate = CmpInst::Predicate(pred);
     bool isIntegerPredicate = ICmpInst::isIntPredicate(Predicate);
@@ -2307,6 +2334,9 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
   Type *GEPTy = GetElementPtrInst::getGEPReturnType(
       PointeeTy, C, makeArrayRef((Value *const *)Idxs.data(), Idxs.size()));
 
+  if (isa<PoisonValue>(C))
+    return PoisonValue::get(GEPTy);
+
   if (isa<UndefValue>(C))
     return UndefValue::get(GEPTy);
 

diff  --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index 764d32e39b05..7ebe461fd0c2 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -418,6 +418,9 @@ Constant *Constant::getAggregateElement(unsigned Elt) const {
   if (const auto *CAZ = dyn_cast<ConstantAggregateZero>(this))
     return Elt < CAZ->getNumElements() ? CAZ->getElementValue(Elt) : nullptr;
 
+  if (const auto *PV = dyn_cast<PoisonValue>(this))
+    return Elt < PV->getNumElements() ? PV->getElementValue(Elt) : nullptr;
+
   if (const auto *UV = dyn_cast<UndefValue>(this))
     return Elt < UV->getNumElements() ? UV->getElementValue(Elt) : nullptr;
 

diff  --git a/llvm/test/Transforms/InstSimplify/ConstProp/InsertElement.ll b/llvm/test/Transforms/InstSimplify/ConstProp/InsertElement.ll
index 98ba4c6f0036..a9a27a5df01f 100644
--- a/llvm/test/Transforms/InstSimplify/ConstProp/InsertElement.ll
+++ b/llvm/test/Transforms/InstSimplify/ConstProp/InsertElement.ll
@@ -37,7 +37,7 @@ define <4 x i64> @insertelement_undef() {
 
 define i64 @extract_undef_index_from_zero_vec() {
 ; CHECK-LABEL: @extract_undef_index_from_zero_vec(
-; CHECK-NEXT:    ret i64 undef
+; CHECK-NEXT:    ret i64 poison
 ;
   %E = extractelement <2 x i64> zeroinitializer, i64 undef
   ret i64 %E
@@ -45,7 +45,7 @@ define i64 @extract_undef_index_from_zero_vec() {
 
 define i64 @extract_undef_index_from_nonzero_vec() {
 ; CHECK-LABEL: @extract_undef_index_from_nonzero_vec(
-; CHECK-NEXT:    ret i64 undef
+; CHECK-NEXT:    ret i64 poison
 ;
   %E = extractelement <2 x i64> <i64 -1, i64 -1>, i64 undef
   ret i64 %E

diff  --git a/llvm/test/Transforms/InstSimplify/ConstProp/poison.ll b/llvm/test/Transforms/InstSimplify/ConstProp/poison.ll
new file mode 100644
index 000000000000..b35456e5470b
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/ConstProp/poison.ll
@@ -0,0 +1,116 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+declare void @use(...)
+
+define void @casts() {
+; CHECK-LABEL: @casts(
+; CHECK-NEXT:    call void (...) @use(i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i32 poison, i8 poison, float poison, float poison, float poison, float poison)
+; CHECK-NEXT:    ret void
+;
+  %i1 = trunc i32 poison to i8
+  %i2 = zext i4 poison to i8
+  %i3 = sext i4 poison to i8
+  %i4 = fptoui float poison to i8
+  %i5 = fptosi float poison to i8
+  %i6 = bitcast float poison to i32
+  %i7 = ptrtoint i8* poison to i8
+  %f1 = fptrunc double poison to float
+  %f2 = fpext half poison to float
+  %f3 = uitofp i8 poison to float
+  %f4 = sitofp i8 poison to float
+  call void (...) @use(i8 %i1, i8 %i2, i8 %i3, i8 %i4, i8 %i5, i32 %i6, i8 %i7, float %f1, float %f2, float %f3, float %f4)
+  ret void
+}
+
+define void @casts2() {
+; CHECK-LABEL: @casts2(
+; CHECK-NEXT:    call void (...) @use(i8* poison, i8* poison)
+; CHECK-NEXT:    ret void
+;
+  %p1 = inttoptr i8 poison to i8*
+  %p2 = addrspacecast i8 addrspace(1)* poison to i8*
+  call void (...) @use(i8* %p1, i8* %p2)
+  ret void
+}
+
+define void @unaryops() {
+; CHECK-LABEL: @unaryops(
+; CHECK-NEXT:    call void (...) @use(float poison)
+; CHECK-NEXT:    ret void
+;
+  %f1 = fneg float poison
+  call void (...) @use(float %f1)
+  ret void
+}
+
+define void @binaryops_arith() {
+; CHECK-LABEL: @binaryops_arith(
+; CHECK-NEXT:    call void (...) @use(i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison)
+; CHECK-NEXT:    ret void
+;
+  %i1 = add i8 poison, 1
+  %i2 = sub i8 poison, 1
+  %i3 = mul i8 poison, 2
+  %i4 = udiv i8 poison, 2
+  %i5 = udiv i8 2, poison
+  %i6 = sdiv i8 poison, 2
+  %i7 = sdiv i8 2, poison
+  %i8 = urem i8 poison, 2
+  %i9 = urem i8 2, poison
+  %i10 = srem i8 poison, 2
+  %i11 = srem i8 2, poison
+  %f1 = fadd float poison, 1.0
+  %f2 = fsub float poison, 1.0
+  %f3 = fmul float poison, 2.0
+  %f4 = fdiv float poison, 2.0
+  %f5 = fdiv float 2.0, poison
+  %f6 = frem float poison, 2.0
+  %f7 = frem float 2.0, poison
+  call void (...) @use(i8 %i1, i8 %i2, i8 %i3, i8 %i4, i8 %i5, i8 %i6, i8 %i7, i8 %i8, i8 %i9, i8 %i10, i8 %i11, float %f1, float %f2, float %f3, float %f4, float %f5, float %f6, float %f7)
+  ret void
+}
+
+define void @binaryops_bitwise() {
+; CHECK-LABEL: @binaryops_bitwise(
+; CHECK-NEXT:    call void (...) @use(i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison)
+; CHECK-NEXT:    ret void
+;
+  %i1 = shl i8 poison, 1
+  %i2 = shl i8 1, poison
+  %i3 = lshr i8 poison, 1
+  %i4 = lshr i8 1, poison
+  %i5 = ashr i8 poison, 1
+  %i6 = ashr i8 1, poison
+  %i7 = and i8 poison, 1
+  %i8 = or i8 poison, 1
+  %i9 = xor i8 poison, 1
+  call void (...) @use(i8 %i1, i8 %i2, i8 %i3, i8 %i4, i8 %i5, i8 %i6, i8 %i7, i8 %i8, i8 %i9)
+  ret void
+}
+
+define void @vec_aggr_ops() {
+; CHECK-LABEL: @vec_aggr_ops(
+; CHECK-NEXT:    call void (...) @use(i8 poison, i8 poison, <2 x i8> poison, i8 poison)
+; CHECK-NEXT:    ret void
+;
+  %i1 = extractelement <2 x i8> poison, i64 0
+  %i2 = extractelement <2 x i8> zeroinitializer, i64 poison
+  %i3 = insertelement <2 x i8> zeroinitializer, i8 0, i64 poison
+  %i4 = extractvalue {i8, i8} poison, 0
+  call void (...) @use(i8 %i1, i8 %i2, <2 x i8> %i3, i8 %i4)
+  ret void
+}
+
+define void @other_ops(i8 %x) {
+; CHECK-LABEL: @other_ops(
+; CHECK-NEXT:    call void (...) @use(i1 poison, i1 poison, i8 poison, i8 poison, i8* poison)
+; CHECK-NEXT:    ret void
+;
+  %i1 = icmp eq i8 poison, 1
+  %i2 = fcmp oeq float poison, 1.0
+  %i3 = select i1 poison, i8 1, i8 2
+  %i4 = select i1 true, i8 poison, i8 %x
+  call void (...) @use(i1 %i1, i1 %i2, i8 %i3, i8 %i4, i8* getelementptr (i8, i8* poison, i64 1))
+  ret void
+}

diff  --git a/llvm/unittests/IR/ConstantsTest.cpp b/llvm/unittests/IR/ConstantsTest.cpp
index 5fb2d2dfc7ac..e1e45c7ae856 100644
--- a/llvm/unittests/IR/ConstantsTest.cpp
+++ b/llvm/unittests/IR/ConstantsTest.cpp
@@ -216,9 +216,10 @@ TEST(ConstantsTest, AsInstructionsTest) {
   Constant *Two = ConstantInt::get(Int64Ty, 2);
   Constant *Big = ConstantInt::get(Context, APInt{256, uint64_t(-1), true});
   Constant *Elt = ConstantInt::get(Int16Ty, 2015);
-  Constant *Undef16  = UndefValue::get(Int16Ty);
+  Constant *Poison16 = PoisonValue::get(Int16Ty);
   Constant *Undef64  = UndefValue::get(Int64Ty);
   Constant *UndefV16 = UndefValue::get(P6->getType());
+  Constant *PoisonV16 = PoisonValue::get(P6->getType());
 
   #define P0STR "ptrtoint (i32** @dummy to i32)"
   #define P1STR "uitofp (i32 ptrtoint (i32** @dummy to i32) to float)"
@@ -288,15 +289,15 @@ TEST(ConstantsTest, AsInstructionsTest) {
   CHECK(ConstantExpr::getExtractElement(P6, One), "extractelement <2 x i16> "
         P6STR ", i32 1");
 
-  EXPECT_EQ(Undef16, ConstantExpr::getExtractElement(P6, Two));
-  EXPECT_EQ(Undef16, ConstantExpr::getExtractElement(P6, Big));
-  EXPECT_EQ(Undef16, ConstantExpr::getExtractElement(P6, Undef64));
+  EXPECT_EQ(Poison16, ConstantExpr::getExtractElement(P6, Two));
+  EXPECT_EQ(Poison16, ConstantExpr::getExtractElement(P6, Big));
+  EXPECT_EQ(Poison16, ConstantExpr::getExtractElement(P6, Undef64));
 
   EXPECT_EQ(Elt, ConstantExpr::getExtractElement(
                  ConstantExpr::getInsertElement(P6, Elt, One), One));
   EXPECT_EQ(UndefV16, ConstantExpr::getInsertElement(P6, Elt, Two));
   EXPECT_EQ(UndefV16, ConstantExpr::getInsertElement(P6, Elt, Big));
-  EXPECT_EQ(UndefV16, ConstantExpr::getInsertElement(P6, Elt, Undef64));
+  EXPECT_EQ(PoisonV16, ConstantExpr::getInsertElement(P6, Elt, Undef64));
 }
 
 #ifdef GTEST_HAS_DEATH_TEST


        


More information about the llvm-branch-commits mailing list