diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp --- a/llvm/lib/IR/ConstantFold.cpp +++ b/llvm/lib/IR/ConstantFold.cpp @@ -522,6 +522,9 @@ Constant *llvm::ConstantFoldCastInstruction(unsigned opc, Constant *V, Type *DestTy) { + if (isa(V)) + return PoisonValue::get(DestTy); + if (isa(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 *V2Element = ConstantExpr::getExtractElement(V2, ConstantInt::get(Ty, i)); auto *Cond = cast(CondV->getOperand(i)); - if (V1Element == V2Element) { + if (isa(Cond)) { + V = PoisonValue::get(V1Element->getType()); + } else if (V1Element == V2Element) { V = V1Element; } else if (isa(Cond)) { V = isa(V1Element) ? V1Element : V2Element; @@ -775,6 +780,9 @@ return ConstantVector::get(Result); } + if (isa(Cond)) + return PoisonValue::get(V1->getType()); + if (isa(Cond)) { if (isa(V1)) return V1; return V2; @@ -782,9 +790,17 @@ if (V1 == V2) return V1; + if (isa(V1)) + return V2; + if (isa(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(C)) + return false; + // TODO: We can analyze ConstExpr by opcode to determine if there is any // possibility of poison. if (isa(C)) @@ -821,9 +837,13 @@ Constant *Idx) { auto *ValVTy = cast(Val->getType()); + // extractelt poison, C -> poison + // extractelt C, undef -> poison + if (isa(Val) || isa(Idx)) + return PoisonValue::get(ValVTy->getElementType()); + // extractelt undef, C -> undef - // extractelt C, undef -> undef - if (isa(Val) || isa(Idx)) + if (isa(Val)) return UndefValue::get(ValVTy->getElementType()); auto *CIdx = dyn_cast(Idx); @@ -831,9 +851,9 @@ return nullptr; if (auto *ValFVTy = dyn_cast(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 *Elt, Constant *Idx) { if (isa(Idx)) - return UndefValue::get(Val->getType()); + return PoisonValue::get(Val->getType()); ConstantInt *CIdx = dyn_cast(Idx); if (!CIdx) return nullptr; @@ -1084,12 +1104,15 @@ return C1; } - // Handle scalar UndefValue and scalable vector UndefValue. Fixed-length - // vectors are always evaluated per element. + // Handle scalar Poison/UndefValue and scalable vector Poison/UndefValue. + // Fixed-length vectors are always evaluated per element. bool IsScalableVector = isa(C1->getType()); + bool IsScalarOrScalarVec = !C1->getType()->isVectorTy() || IsScalableVector; + if (IsScalarOrScalarVec && (isa(C1) || isa(C2))) + return isa(C1) ? C1 : C2; + bool HasScalarUndefOrScalableVectorUndef = - (!C1->getType()->isVectorTy() || IsScalableVector) && - (isa(C1) || isa(C2)); + IsScalarOrScalarVec && (isa(C1) || isa(C2)); if (HasScalarUndefOrScalableVectorUndef) { switch (static_cast(Opcode)) { case Instruction::Xor: @@ -1922,6 +1945,9 @@ return Constant::getAllOnesValue(ResultTy); // Handle some degenerate cases first + if (isa(C1) || isa(C2)) + return PoisonValue::get(ResultTy); + if (isa(C1) || isa(C2)) { CmpInst::Predicate Predicate = CmpInst::Predicate(pred); bool isIntegerPredicate = ICmpInst::isIntPredicate(Predicate); @@ -2307,6 +2333,9 @@ Type *GEPTy = GetElementPtrInst::getGEPReturnType( PointeeTy, C, makeArrayRef((Value *const *)Idxs.data(), Idxs.size())); + if (isa(C)) + return PoisonValue::get(GEPTy); + if (isa(C)) return UndefValue::get(GEPTy); diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -418,6 +418,9 @@ if (const auto *CAZ = dyn_cast(this)) return Elt < CAZ->getNumElements() ? CAZ->getElementValue(Elt) : nullptr; + if (const auto *PV = dyn_cast(this)) + return Elt < PV->getNumElements() ? PV->getElementValue(Elt) : nullptr; + if (const auto *UV = dyn_cast(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 --- a/llvm/test/Transforms/InstSimplify/ConstProp/InsertElement.ll +++ b/llvm/test/Transforms/InstSimplify/ConstProp/InsertElement.ll @@ -37,7 +37,7 @@ 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_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 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 --- /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 --- a/llvm/unittests/IR/ConstantsTest.cpp +++ b/llvm/unittests/IR/ConstantsTest.cpp @@ -216,9 +216,10 @@ 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 @@ 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