Index: llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp =================================================================== --- llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp +++ llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp @@ -36,6 +36,92 @@ #define DEBUG_TYPE "aggressive-instcombine" +// Get the minimum number of bits needed for representing the given constant. +// This function assumes the constant is of a scalar type. +static unsigned getConstMinBitWidthScalar(bool IsSigned, Constant *C) { + assert(!C->getType()->isVectorTy() && + "getConstMinBitWidthScalar accepts scalar constants only"); + + if (ConstantInt *CI = dyn_cast(C)) { + const APInt &Val = CI->getValue(); + return IsSigned ? Val.getMinSignedBits() : Val.getActiveBits(); + } + return C->getType()->getScalarSizeInBits(); +} + +// Get the minimum number of bits needed for the given constant. +static unsigned getConstMinBitWidth(bool IsSigned, Constant *C) { + Type *VT = C->getType(); + unsigned Min = 0; + // In case of a constant vector, make sure all constant elements can fit in + // the given type. + if (VT->isVectorTy()) { + for (unsigned i = 0; i < VT->getVectorNumElements(); i++) { + unsigned MinCurr = + getConstMinBitWidthScalar(IsSigned, C->getAggregateElement(i)); + Min = std::max(MinCurr, Min); + } + return Min; + } + return getConstMinBitWidthScalar(IsSigned, C); +} + +// If @Ty is NULL, returns true if the provided ICmp instruction is a candidate +// to be shrunk. +// If @Ty is not NULL, returns true if the provided ICmp instruction can be +// shrunk to the given type @Ty shrunk. +static bool CmpCanBeShrunk(ICmpInst *I, Type *Ty = nullptr) { + bool HasConst = false; + unsigned MinScalarTypeInBits = + I->getOperand(0)->getType()->getScalarSizeInBits(); + bool IsSigned = I->isSigned(); + + for (auto &V : I->operands()) { + if (Constant *C = dyn_cast(V)) { + // If Op is a constant, make sure it fits in Ty in case it was provided. + if (Ty && Ty->getScalarSizeInBits() < getConstMinBitWidth(IsSigned, C)) + return false; + + // Mark that one of the operands is a constant. + HasConst = true; + continue; + } + + if (Instruction *I = dyn_cast(V)) { + switch (I->getOpcode()) { + case Instruction::ZExt: + case Instruction::SExt: { + // In case of sext/zext, make sure the original type can fit in @Ty if + // provided. + unsigned SclSize = cast(I)->getSrcTy()->getScalarSizeInBits(); + if (Ty && Ty->getScalarSizeInBits() < SclSize) + return false; + MinScalarTypeInBits = std::min(MinScalarTypeInBits, SclSize); + continue; + } + } + } + return false; + } + + // If both operands are valid, check that the combination is valid as well. + // If one of them is a constant, return true. + if (HasConst) + return true; + + // If the type to be shrunk to is larger than the src types of both extend + // instructions, return true; + if (Ty && Ty->getScalarSizeInBits() > MinScalarTypeInBits) + return true; + + // If the type to be shrunk to is equal to the src type of at least one of + // the extend instructions, make sure the opcodes are identical, except for + // the case where the compare is signed and the extend operations are ZExt. + unsigned Opc0 = cast(I->getOperand(0))->getOpcode(); + unsigned Opc1 = cast(I->getOperand(1))->getOpcode(); + return (!Ty || (Opc0 == Opc1 && !(IsSigned && Opc0 == Instruction::ZExt))); +} + /// Given an instruction and a container, it fills all the relevant operands of /// that instruction, with respect to the Trunc expression dag optimizaton. static void getRelevantOperands(Instruction *I, SmallVectorImpl &Ops) { @@ -53,13 +139,22 @@ case Instruction::And: case Instruction::Or: case Instruction::Xor: + case Instruction::ICmp: Ops.push_back(I->getOperand(0)); Ops.push_back(I->getOperand(1)); break; - case Instruction::Select: + case Instruction::Select: { + Value *Op0 = I->getOperand(0); Ops.push_back(I->getOperand(1)); Ops.push_back(I->getOperand(2)); + // In case the condition is a compare instruction, that both of its operands + // are a type extension/truncate or a constant, that can be shrunk without + // loosing information in the compare instruction, add them as well. + if (ICmpInst *C = dyn_cast(Op0)) + if (CmpCanBeShrunk(C)) + Ops.push_back(Op0); break; + } default: llvm_unreachable("Unreachable!"); } @@ -119,7 +214,8 @@ case Instruction::And: case Instruction::Or: case Instruction::Xor: - case Instruction::Select: { + case Instruction::Select: + case Instruction::ICmp: { SmallVector Operands; getRelevantOperands(I, Operands); for (Value *Operand : Operands) @@ -356,11 +452,21 @@ } case Instruction::Select: { Value *Op0 = I->getOperand(0); + if (ICmpInst *C = dyn_cast(Op0)) + if (CmpCanBeShrunk(C, SclTy)) + Op0 = getReducedOperand(Op0, SclTy); Value *LHS = getReducedOperand(I->getOperand(1), SclTy); Value *RHS = getReducedOperand(I->getOperand(2), SclTy); Res = Builder.CreateSelect(Op0, LHS, RHS); break; } + case Instruction::ICmp: { + auto ICmp = cast(I); + Value *LHS = getReducedOperand(ICmp->getOperand(0), SclTy); + Value *RHS = getReducedOperand(ICmp->getOperand(1), SclTy); + Res = Builder.CreateICmp(ICmp->getPredicate(), LHS, RHS); + break; + } default: llvm_unreachable("Unhandled instruction"); } Index: llvm/test/Transforms/AggressiveInstCombine/trunc_select_cmp.ll =================================================================== --- llvm/test/Transforms/AggressiveInstCombine/trunc_select_cmp.ll +++ llvm/test/Transforms/AggressiveInstCombine/trunc_select_cmp.ll @@ -1,15 +1,20 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -aggressive-instcombine -S | FileCheck %s -; RUN: opt < %s -passes=aggressive-instcombine -S | FileCheck %s +; RUN: opt < %s -aggressive-instcombine -dce -S | FileCheck %s + +; Today, InstCombine cannot handle the following cases since it doesn't +; allow - in any way - an instruction with multiple uses to be shrunk. +; Aggressive InstCombine, on the other hand, remembers all the nodes we +; want to shrink, and in case of an instruction with multiple uses, it +; makes sure that all uses are gonna be shrunk as well, thus allowing +; the transformation to happen. define dso_local i16 @cmp_select_sext_const(i8 %a) { ; CHECK-LABEL: @cmp_select_sext_const( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[A:%.*]] to i32 -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CONV]], 109 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 109, i32 [[CONV]] -; CHECK-NEXT: [[CONV4:%.*]] = trunc i32 [[COND]] to i16 -; CHECK-NEXT: ret i16 [[CONV4]] +; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[CONV]], 109 +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i16 109, i16 [[CONV]] +; CHECK-NEXT: ret i16 [[COND]] ; entry: %conv = sext i8 %a to i32 @@ -22,12 +27,11 @@ define dso_local i16 @cmp_select_sext(i8 %a, i8 %b) { ; CHECK-LABEL: @cmp_select_sext( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[A:%.*]] to i32 -; CHECK-NEXT: [[CONV2:%.*]] = sext i8 [[B:%.*]] to i32 -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CONV]], [[CONV2]] -; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[CONV2]], i32 [[CONV]] -; CHECK-NEXT: [[CONV4:%.*]] = trunc i32 [[COND]] to i16 -; CHECK-NEXT: ret i16 [[CONV4]] +; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[CONV2:%.*]] = sext i8 [[B:%.*]] to i16 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[CONV]], [[CONV2]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i16 [[CONV2]], i16 [[CONV]] +; CHECK-NEXT: ret i16 [[COND]] ; entry: %conv = sext i8 %a to i32 @@ -41,12 +45,11 @@ define dso_local i16 @cmp_select_zext(i8 %a, i8 %b) { ; CHECK-LABEL: @cmp_select_zext( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i32 -; CHECK-NEXT: [[CONV2:%.*]] = zext i8 [[B:%.*]] to i32 -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CONV]], [[CONV2]] -; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[CONV2]], i32 [[CONV]] -; CHECK-NEXT: [[CONV4:%.*]] = trunc i32 [[COND]] to i16 -; CHECK-NEXT: ret i16 [[CONV4]] +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[CONV2:%.*]] = zext i8 [[B:%.*]] to i16 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[CONV]], [[CONV2]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i16 [[CONV2]], i16 [[CONV]] +; CHECK-NEXT: ret i16 [[COND]] ; entry: %conv = zext i8 %a to i32 @@ -57,15 +60,32 @@ ret i16 %conv4 } +define dso_local i8 @cmp_select_zext_i8_noTransformation(i8 %a, i8 %b) { +; CHECK-LABEL: @cmp_select_zext_i8_noTransformation( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i32 +; CHECK-NEXT: [[CONV2:%.*]] = zext i8 [[B:%.*]] to i32 +; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[CONV]], [[CONV2]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[TMP0]], i8 [[B]], i8 [[A]] +; CHECK-NEXT: ret i8 [[COND]] +; +entry: + %conv = zext i8 %a to i32 + %conv2 = zext i8 %b to i32 + %cmp = icmp slt i32 %conv, %conv2 + %cond = select i1 %cmp, i32 %conv2, i32 %conv + %conv4 = trunc i32 %cond to i8 + ret i8 %conv4 +} + define dso_local i16 @cmp_select_zext_sext(i8 %a, i8 %b) { ; CHECK-LABEL: @cmp_select_zext_sext( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i32 -; CHECK-NEXT: [[CONV2:%.*]] = sext i8 [[B:%.*]] to i32 -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CONV]], [[CONV2]] -; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[CONV2]], i32 [[CONV]] -; CHECK-NEXT: [[CONV4:%.*]] = trunc i32 [[COND]] to i16 -; CHECK-NEXT: ret i16 [[CONV4]] +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[CONV2:%.*]] = sext i8 [[B:%.*]] to i16 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[CONV]], [[CONV2]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i16 [[CONV2]], i16 [[CONV]] +; CHECK-NEXT: ret i16 [[COND]] ; entry: %conv = zext i8 %a to i32 @@ -76,15 +96,31 @@ ret i16 %conv4 } +define dso_local i8 @cmp_select_zext_sext_i8_noTransformation(i8 %a, i8 %b) { +; CHECK-LABEL: @cmp_select_zext_sext_i8_noTransformation( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i32 +; CHECK-NEXT: [[CONV2:%.*]] = sext i8 [[B:%.*]] to i32 +; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[CONV]], [[CONV2]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[TMP0]], i8 [[B]], i8 [[A]] +; CHECK-NEXT: ret i8 [[COND]] +; +entry: + %conv = zext i8 %a to i32 + %conv2 = sext i8 %b to i32 + %cmp = icmp slt i32 %conv, %conv2 + %cond = select i1 %cmp, i32 %conv2, i32 %conv + %conv4 = trunc i32 %cond to i8 + ret i8 %conv4 +} + define dso_local i16 @cmp_select_zext_sext_diffOrigTy(i8 %a, i16 %b) { ; CHECK-LABEL: @cmp_select_zext_sext_diffOrigTy( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i32 -; CHECK-NEXT: [[CONV2:%.*]] = sext i16 [[B:%.*]] to i32 -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CONV]], [[CONV2]] -; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[CONV2]], i32 [[CONV]] -; CHECK-NEXT: [[CONV4:%.*]] = trunc i32 [[COND]] to i16 -; CHECK-NEXT: ret i16 [[CONV4]] +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[CONV]], [[B:%.*]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i16 [[B]], i16 [[CONV]] +; CHECK-NEXT: ret i16 [[COND]] ; entry: %conv = zext i8 %a to i32 @@ -98,12 +134,11 @@ define dso_local i16 @my_abs_sext(i8 %a) { ; CHECK-LABEL: @my_abs_sext( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[A:%.*]] to i32 -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CONV]], 0 -; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 0, [[CONV]] -; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 [[CONV]] -; CHECK-NEXT: [[CONV4:%.*]] = trunc i32 [[COND]] to i16 -; CHECK-NEXT: ret i16 [[CONV4]] +; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[CONV]], 0 +; CHECK-NEXT: [[SUB:%.*]] = sub i16 0, [[CONV]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i16 [[SUB]], i16 [[CONV]] +; CHECK-NEXT: ret i16 [[COND]] ; entry: %conv = sext i8 %a to i32 @@ -117,12 +152,11 @@ define dso_local i16 @my_abs_zext(i8 %a) { ; CHECK-LABEL: @my_abs_zext( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i32 -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CONV]], 0 -; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 0, [[CONV]] -; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 [[CONV]] -; CHECK-NEXT: [[CONV4:%.*]] = trunc i32 [[COND]] to i16 -; CHECK-NEXT: ret i16 [[CONV4]] +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[CONV]], 0 +; CHECK-NEXT: [[SUB:%.*]] = sub i16 0, [[CONV]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i16 [[SUB]], i16 [[CONV]] +; CHECK-NEXT: ret i16 [[COND]] ; entry: %conv = zext i8 %a to i32 @@ -167,11 +201,11 @@ define i16 @cmp_select_signed_const_i16Const_noTransformation(i8 %a) { ; CHECK-LABEL: @cmp_select_signed_const_i16Const_noTransformation( -; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[A:%.*]] to i32 -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CONV]], 32768 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 32768, i32 [[CONV]] -; CHECK-NEXT: [[CONV4:%.*]] = trunc i32 [[COND]] to i16 -; CHECK-NEXT: ret i16 [[CONV4]] +; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[A]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 32768 +; CHECK-NEXT: [[COND:%.*]] = select i1 [[TMP2]], i16 -32768, i16 [[CONV]] +; CHECK-NEXT: ret i16 [[COND]] ; %conv = sext i8 %a to i32 %cmp = icmp slt i32 %conv, 32768 @@ -182,11 +216,10 @@ define i16 @cmp_select_unsigned_const_i16Const(i8 %a) { ; CHECK-LABEL: @cmp_select_unsigned_const_i16Const( -; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i32 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[CONV]], 32768 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 32768, i32 [[CONV]] -; CHECK-NEXT: [[CONV4:%.*]] = trunc i32 [[COND]] to i16 -; CHECK-NEXT: ret i16 [[CONV4]] +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i16 [[CONV]], -32768 +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i16 -32768, i16 [[CONV]] +; CHECK-NEXT: ret i16 [[COND]] ; %conv = zext i8 %a to i32 %cmp = icmp ult i32 %conv, 32768 @@ -197,11 +230,11 @@ define i16 @cmp_select_unsigned_const_i16Const_noTransformation(i8 %a) { ; CHECK-LABEL: @cmp_select_unsigned_const_i16Const_noTransformation( -; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i32 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[CONV]], 65536 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 65536, i32 [[CONV]] -; CHECK-NEXT: [[CONV4:%.*]] = trunc i32 [[COND]] to i16 -; CHECK-NEXT: ret i16 [[CONV4]] +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[A]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 65536 +; CHECK-NEXT: [[COND:%.*]] = select i1 [[TMP2]], i16 0, i16 [[CONV]] +; CHECK-NEXT: ret i16 [[COND]] ; %conv = zext i8 %a to i32 %cmp = icmp ult i32 %conv, 65536 @@ -210,3 +243,148 @@ ret i16 %conv4 } +define dso_local i16 @cmp_shrink_select_not_cmp(i8 %a, i8 %b, i32 %c, i32 %d) { +; CHECK-LABEL: @cmp_shrink_select_not_cmp( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[CONV2:%.*]] = sext i8 [[B:%.*]] to i16 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[C:%.*]], [[D:%.*]] +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i16 [[CONV2]], i16 [[CONV]] +; CHECK-NEXT: ret i16 [[COND]] +; +entry: + %conv = sext i8 %a to i32 + %conv2 = sext i8 %b to i32 + %cmp = icmp slt i32 %c, %d + %cond = select i1 %cmp, i32 %conv2, i32 %conv + %conv4 = trunc i32 %cond to i16 + ret i16 %conv4 +} + +define i8 @cmp_select_unsigned_const_i16_MSB1(i8 %a) { +; CHECK-LABEL: @cmp_select_unsigned_const_i16_MSB1( +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i16 [[CONV]], -128 +; CHECK-NEXT: [[COND:%.*]] = select i1 [[TMP1]], i8 55, i8 [[A]] +; CHECK-NEXT: ret i8 [[COND]] +; + %conv = zext i8 %a to i16 + %cmp = icmp ult i16 %conv, 65408 + %cond = select i1 %cmp, i16 55, i16 %conv + %conv4 = trunc i16 %cond to i8 + ret i8 %conv4 +} + +define i16 @cmp_select_bigConst_cmp(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: @cmp_select_bigConst_cmp( +; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[A:%.*]] to i16 +; CHECK-NEXT: [[CONV2:%.*]] = sext i8 [[B:%.*]] to i16 +; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[C:%.*]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 70000 +; CHECK-NEXT: [[COND:%.*]] = select i1 [[TMP2]], i16 [[CONV2]], i16 [[CONV]] +; CHECK-NEXT: ret i16 [[COND]] +; + %conv = sext i8 %a to i32 + %conv2 = sext i8 %b to i32 + %conv3 = sext i8 %c to i32 + %cmp = icmp slt i32 %conv3, 70000 + %cond = select i1 %cmp, i32 %conv2, i32 %conv + %conv4 = trunc i32 %cond to i16 + ret i16 %conv4 +} + +define dso_local <2 x i16> @cmp_select_vec_sext(<2 x i8> %a, <2 x i8> %b) { +; CHECK-LABEL: @cmp_select_vec_sext( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CONV:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i16> +; CHECK-NEXT: [[CONV2:%.*]] = sext <2 x i8> [[B:%.*]] to <2 x i16> +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i16> [[CONV]], [[CONV2]] +; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i16> [[CONV2]], <2 x i16> [[CONV]] +; CHECK-NEXT: ret <2 x i16> [[COND]] +; +entry: + %conv = sext <2 x i8> %a to <2 x i32> + %conv2 = sext <2 x i8> %b to <2 x i32> + %cmp = icmp slt <2 x i32> %conv, %conv2 + %cond = select <2 x i1> %cmp, <2 x i32> %conv2, <2 x i32> %conv + %conv4 = trunc <2 x i32> %cond to <2 x i16> + ret <2 x i16> %conv4 +} + +define dso_local <2 x i16> @cmp_select_vec_zext(<2 x i8> %a, <2 x i8> %b) { +; CHECK-LABEL: @cmp_select_vec_zext( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CONV:%.*]] = zext <2 x i8> [[A:%.*]] to <2 x i16> +; CHECK-NEXT: [[CONV2:%.*]] = zext <2 x i8> [[B:%.*]] to <2 x i16> +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i16> [[CONV]], [[CONV2]] +; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i16> [[CONV2]], <2 x i16> [[CONV]] +; CHECK-NEXT: ret <2 x i16> [[COND]] +; +entry: + %conv = zext <2 x i8> %a to <2 x i32> + %conv2 = zext <2 x i8> %b to <2 x i32> + %cmp = icmp slt <2 x i32> %conv, %conv2 + %cond = select <2 x i1> %cmp, <2 x i32> %conv2, <2 x i32> %conv + %conv4 = trunc <2 x i32> %cond to <2 x i16> + ret <2 x i16> %conv4 +} + +define dso_local <2 x i16> @cmp_select_vec_sext_zext(<2 x i8> %a, <2 x i8> %b) { +; CHECK-LABEL: @cmp_select_vec_sext_zext( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CONV:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i16> +; CHECK-NEXT: [[CONV2:%.*]] = zext <2 x i8> [[B:%.*]] to <2 x i16> +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i16> [[CONV]], [[CONV2]] +; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i16> [[CONV2]], <2 x i16> [[CONV]] +; CHECK-NEXT: ret <2 x i16> [[COND]] +; +entry: + %conv = sext <2 x i8> %a to <2 x i32> + %conv2 = zext <2 x i8> %b to <2 x i32> + %cmp = icmp slt <2 x i32> %conv, %conv2 + %cond = select <2 x i1> %cmp, <2 x i32> %conv2, <2 x i32> %conv + %conv4 = trunc <2 x i32> %cond to <2 x i16> + ret <2 x i16> %conv4 +} + +define dso_local <2 x i16> @cmp_select_vec_sext_const(<2 x i8> %a) { +; CHECK-LABEL: @cmp_select_vec_sext_const( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CONV:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i16> +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i16> [[CONV]], +; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i16> , <2 x i16> [[CONV]] +; CHECK-NEXT: ret <2 x i16> [[COND]] +; +entry: + %conv = sext <2 x i8> %a to <2 x i32> + %cmp = icmp slt <2 x i32> %conv, + %cond = select <2 x i1> %cmp, <2 x i32> , <2 x i32> %conv + %conv4 = trunc <2 x i32> %cond to <2 x i16> + ret <2 x i16> %conv4 +} + +define <2 x i8> @cmp_select_unsigned_const_vec_i8_noTransformation(<2 x i8> %a) { +; CHECK-LABEL: @cmp_select_unsigned_const_vec_i8_noTransformation( +; CHECK-NEXT: [[CONV:%.*]] = zext <2 x i8> [[A:%.*]] to <2 x i32> +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult <2 x i32> [[CONV]], +; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[TMP1]], <2 x i8> , <2 x i8> [[A]] +; CHECK-NEXT: ret <2 x i8> [[COND]] +; + %conv = zext <2 x i8> %a to <2 x i32> + %cmp = icmp ult <2 x i32> %conv, + %cond = select <2 x i1> %cmp, <2 x i32> , <2 x i32> %conv + %conv4 = trunc <2 x i32> %cond to <2 x i8> + ret <2 x i8> %conv4 +} + +define i1 @cmp_zext_and_minus1_noTransformation(i16 %a) { +; CHECK-LABEL: @cmp_zext_and_minus1_noTransformation( +; CHECK-NEXT: [[CONV:%.*]] = zext i16 [[A:%.*]] to i32 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[CONV]], -1 +; CHECK-NEXT: ret i1 [[CMP]] +; + %conv = zext i16 %a to i32 + %cmp = icmp ult i32 %conv, -1 + ret i1 %cmp +} +