Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3129,63 +3129,69 @@ } } - // The usual vector types are ConstantDataVector. Exotic vector types are - // ConstantVector. Zeros are special. They all derive from Constant. - if (isa(Op1) || isa(Op1) || - isa(Op1)) { - Constant *Op1C = cast(Op1); - Type *Op1Type = Op1->getType(); - unsigned NumElts = Op1Type->getVectorNumElements(); - - // Set the new comparison predicate and splat a vector of 1 or -1 to - // increment or decrement the vector constants. But first, check that no - // elements of the constant vector would overflow/underflow when we - // increment/decrement the constants. - // - // TODO? If the edge cases for vectors were guaranteed to be handled as they - // are for scalar, we could remove the min/max checks here. However, to do - // that, we would have to use insertelement/shufflevector to replace edge - // values. - - CmpInst::Predicate NewPred; - Constant *OneOrNegOne = nullptr; - switch (I.getPredicate()) { - case ICmpInst::ICMP_ULE: - for (unsigned i = 0; i != NumElts; ++i) - if (cast(Op1C->getAggregateElement(i))->isMaxValue(false)) - return nullptr; - NewPred = ICmpInst::ICMP_ULT; - OneOrNegOne = ConstantInt::get(Op1Type, 1); - break; - case ICmpInst::ICMP_SLE: - for (unsigned i = 0; i != NumElts; ++i) - if (cast(Op1C->getAggregateElement(i))->isMaxValue(true)) - return nullptr; - NewPred = ICmpInst::ICMP_SLT; - OneOrNegOne = ConstantInt::get(Op1Type, 1); - break; - case ICmpInst::ICMP_UGE: - for (unsigned i = 0; i != NumElts; ++i) - if (cast(Op1C->getAggregateElement(i))->isMinValue(false)) - return nullptr; - NewPred = ICmpInst::ICMP_UGT; - OneOrNegOne = ConstantInt::get(Op1Type, -1); - break; - case ICmpInst::ICMP_SGE: - for (unsigned i = 0; i != NumElts; ++i) - if (cast(Op1C->getAggregateElement(i))->isMinValue(true)) - return nullptr; - NewPred = ICmpInst::ICMP_SGT; - OneOrNegOne = ConstantInt::get(Op1Type, -1); - break; - default: - return nullptr; + // For vectors, try the same transform, but we must handle the edge cases. + auto *Op1C = dyn_cast(Op1); + Type *Op1Type = Op1->getType(); + if (!Op1C || !Op1Type->isVectorTy()) + return nullptr; + + // Check if all elements of the constant can be safely incremented/decremented + // without overflowing/underflowing. + auto allElementsValid = [](Constant *VecConst, bool IsLT, bool IsSigned) { + unsigned NumElts = VecConst->getType()->getVectorNumElements(); + for (unsigned i = 0; i != NumElts; ++i) { + Constant *Elt = VecConst->getAggregateElement(i); + if (isa(Elt)) + continue; + // Bail out if we can't determine if this constant is min/max or if we + // know that this constant is min/max. + auto *CI = dyn_cast(Elt); + if (!CI || (IsLT ? CI->isMaxValue(IsSigned) : CI->isMinValue(IsSigned))) + return false; } + return true; + }; + + // Set the new comparison predicate and splat a vector of 1 or -1 to increment + // or decrement the vector constants. + // + // TODO? If the edge cases for vectors were guaranteed to be handled as they + // are for scalar, we could remove the min/max checks here. However, to do + // that, we would have to use insertelement/shufflevector to replace edge + // values. - return new ICmpInst(NewPred, Op0, ConstantExpr::getAdd(Op1C, OneOrNegOne)); + CmpInst::Predicate NewPred; + Constant *OneOrNegOne = nullptr; + switch (I.getPredicate()) { + case ICmpInst::ICMP_ULE: + if (!allElementsValid(Op1C, true, false)) + return nullptr; + NewPred = ICmpInst::ICMP_ULT; + OneOrNegOne = ConstantInt::get(Op1Type, 1); + break; + case ICmpInst::ICMP_SLE: + if (!allElementsValid(Op1C, true, true)) + return nullptr; + NewPred = ICmpInst::ICMP_SLT; + OneOrNegOne = ConstantInt::get(Op1Type, 1); + break; + case ICmpInst::ICMP_UGE: + if (!allElementsValid(Op1C, false, false)) + return nullptr; + NewPred = ICmpInst::ICMP_UGT; + OneOrNegOne = ConstantInt::get(Op1Type, -1); + break; + case ICmpInst::ICMP_SGE: + if (!allElementsValid(Op1C, false, true)) + return nullptr; + NewPred = ICmpInst::ICMP_SGT; + OneOrNegOne = ConstantInt::get(Op1Type, -1); + break; + default: + return nullptr; } - return nullptr; + return new ICmpInst(NewPred, Op0, ConstantExpr::getAdd(Op1C, OneOrNegOne)); } Instruction *InstCombiner::visitICmpInst(ICmpInst &I) { Index: test/Transforms/InstCombine/icmp-vec.ll =================================================================== --- test/Transforms/InstCombine/icmp-vec.ll +++ test/Transforms/InstCombine/icmp-vec.ll @@ -159,3 +159,25 @@ ret <2 x i1> %cmp } +; If we can't determine if a constant element is min/max (eg, it's a ConstantExpr), do nothing. + +define <2 x i1> @PR27756_1(<2 x i8> %a) { +; CHECK-LABEL: @PR27756_1( +; CHECK-NEXT: [[CMP:%.*]] = icmp sle <2 x i8> %a, to i8), i8 0> +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %cmp = icmp sle <2 x i8> %a, to i8), i8 0> + ret <2 x i1> %cmp +} + +; Undef elements don't prevent the transform of the comparison. + +define <2 x i1> @PR27756_2(<2 x i8> %a) { +; CHECK-LABEL: @PR27756_2( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> %a, +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %cmp = icmp sle <2 x i8> %a, + ret <2 x i1> %cmp +} +