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 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits