Index: include/llvm/IR/Constant.h =================================================================== --- include/llvm/IR/Constant.h +++ include/llvm/IR/Constant.h @@ -87,6 +87,9 @@ /// floating-point constant with all NaN elements. bool isNaN() const; + /// Return true if this is a vector constant that includes undefined elements. + bool containsUndefElements() const; + /// Return true if evaluation of this constant could trap. This is true for /// things like constant expressions that could divide by zero. bool canTrap() const; Index: lib/IR/Constants.cpp =================================================================== --- lib/IR/Constants.cpp +++ lib/IR/Constants.cpp @@ -254,6 +254,16 @@ return true; } +bool Constant::containsUndefElements() const { + if (!getType()->isVectorTy()) + return false; + for (unsigned i = 0, e = getType()->getVectorNumElements(); i != e; ++i) + if (isa(getAggregateElement(i))) + return true; + + return false; +} + /// Constructor to create a '0' constant of arbitrary type. Constant *Constant::getNullValue(Type *Ty) { switch (Ty->getTypeID()) { Index: lib/Transforms/InstCombine/InstCombineVectorOps.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineVectorOps.cpp +++ lib/Transforms/InstCombine/InstCombineVectorOps.cpp @@ -1182,6 +1182,24 @@ return {}; } +/// Helper function for the shuffle transforms below. If a constant operand +/// contains undefs, we can not safely propagate poison-generating flags to the +/// instruction. The flags would allow other transforms to assume this binop +/// produces poison when there might have been no poison potential in the +/// original code. We choose to drop the flags rather than replace the undef +/// values with safe constants because that is more likely to be better for +/// further analysis and codegen. +static BinaryOperator *getPoisonSafeVectorInst(BinaryOperator *BO) { + assert(BO->getType()->isVectorTy() && + "Undef with poison special-case only applies to vector types"); + Constant *C; + if (match(BO->getOperand(0), m_Constant(C)) || + match(BO->getOperand(1), m_Constant(C))) + if (C->containsUndefElements()) + BO->dropPoisonGeneratingFlags(); + return BO; +} + static Instruction *foldSelectShuffleWith1Binop(ShuffleVectorInst &Shuf) { assert(Shuf.isSelect() && "Must have select-equivalent shuffle"); @@ -1221,9 +1239,9 @@ // shuf (bop X, C), X, M --> bop X, C' // shuf X, (bop X, C), M --> bop X, C' - Instruction *NewBO = BinaryOperator::Create(BOpcode, X, NewC); + auto *NewBO = BinaryOperator::Create(BOpcode, X, NewC); NewBO->copyIRFlags(BO); - return NewBO; + return getPoisonSafeVectorInst(NewBO); } /// Try to fold shuffles that are the equivalent of a vector select. @@ -1318,15 +1336,18 @@ if (Instruction::isIntDivRem(BOpc)) NewC = getSafeVectorConstantForIntDivRem(NewC); - Instruction *NewBO = ConstantsAreOp1 ? BinaryOperator::Create(BOpc, V, NewC) : - BinaryOperator::Create(BOpc, NewC, V); + auto *NewBO = ConstantsAreOp1 ? BinaryOperator::Create(BOpc, V, NewC) : + BinaryOperator::Create(BOpc, NewC, V); // Flags are intersected from the 2 source binops. NewBO->copyIRFlags(B0); NewBO->andIRFlags(B1); if (DropNSW) NewBO->setHasNoSignedWrap(false); - return NewBO; + + // We handled div/rem and a special-case for mul above, but there's one more + // problem with undef/poison. + return getPoisonSafeVectorInst(NewBO); } Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) { Index: test/Transforms/InstCombine/shuffle_select.ll =================================================================== --- test/Transforms/InstCombine/shuffle_select.ll +++ test/Transforms/InstCombine/shuffle_select.ll @@ -29,11 +29,11 @@ ; If any element of the shuffle mask operand is undef, that element of the result is undef. ; The shuffle is eliminated in this transform, but we can replace a constant element with undef. -; Preserve flags when possible. +; Preserve flags when possible. It's not safe to propagate poison-generating flags with undef constants. define <4 x i32> @mul(<4 x i32> %v) { ; CHECK-LABEL: @mul( -; CHECK-NEXT: [[S:%.*]] = mul nuw nsw <4 x i32> [[V:%.*]], +; CHECK-NEXT: [[S:%.*]] = mul <4 x i32> [[V:%.*]], ; CHECK-NEXT: ret <4 x i32> [[S]] ; %b = mul nsw nuw <4 x i32> %v, @@ -277,11 +277,11 @@ ret <4 x i32> %t3 } -; Preserve flags when possible. +; Preserve flags when possible. It's not safe to propagate poison-generating flags with undef constants. define <4 x i32> @shl_shl(<4 x i32> %v0) { ; CHECK-LABEL: @shl_shl( -; CHECK-NEXT: [[T3:%.*]] = shl nuw <4 x i32> [[V0:%.*]], +; CHECK-NEXT: [[T3:%.*]] = shl <4 x i32> [[V0:%.*]], ; CHECK-NEXT: ret <4 x i32> [[T3]] ; %t1 = shl nuw <4 x i32> %v0, @@ -513,12 +513,12 @@ ret <4 x i32> %t3 } -; Preserve flags when possible. +; Preserve flags when possible. It's not safe to propagate poison-generating flags with undef constants. define <4 x i32> @shl_2_vars(<4 x i32> %v0, <4 x i32> %v1) { ; CHECK-LABEL: @shl_2_vars( ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <4 x i32> [[V0:%.*]], <4 x i32> [[V1:%.*]], <4 x i32> -; CHECK-NEXT: [[T3:%.*]] = shl nsw <4 x i32> [[TMP1]], +; CHECK-NEXT: [[T3:%.*]] = shl <4 x i32> [[TMP1]], ; CHECK-NEXT: ret <4 x i32> [[T3]] ; %t1 = shl nsw <4 x i32> %v0,