diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index ba5568b00441b..113dc971bb88d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -3119,6 +3119,127 @@ static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC) { return nullptr; } +static Value *combineOrOfImmCmpToBitExtract(Instruction &Or, + InstCombiner::BuilderTy &Builder, + const DataLayout &DL) { + + auto isICmpEqImm = [](Value *N, ConstantInt *&Imm, Value *&X) -> bool { + if (X) + return match(N, m_OneUse(m_SpecificICmp(ICmpInst::ICMP_EQ, m_Specific(X), + m_ConstantInt(Imm)))); + + return match(N, m_OneUse(m_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(X), + m_ConstantInt(Imm)))); + }; + + // %srl = lshr %bitmap, %X + // %icmp = icmp ult %X, %max_value + // %trunc = trunc %srl to i1 + // %sel = select %icmp, %trunc, false + auto CreateBitExtractSeq = [&](APInt BitMap, APInt MaxValue, + Value *X) -> Value * { + LLVMContext &Context = Or.getContext(); + + // %srl = lshr %bitmap, %X + // It is okay for the shift amount to be truncated because + // if information is lost then it is garunteed to fail the bounds + // check and the shift result will be discarded + ConstantInt *BitMapConst = ConstantInt::get(Context, BitMap); + Value *ShiftAmt = + Builder.CreateZExtOrTrunc(X, BitMapConst->getIntegerType()); + Value *LShr = Builder.CreateLShr(BitMapConst, ShiftAmt); + + // %icmp = icmp ult %X, %max_value + // Use the type that is the larger of 'X' and the bounds integer + // so that no information is lost + Value *MaxVal = ConstantInt::get(Context, MaxValue); + if (MaxVal->getType()->getIntegerBitWidth() > + X->getType()->getIntegerBitWidth()) + X = Builder.CreateZExt(X, MaxVal->getType()); + else + MaxVal = Builder.CreateZExt(MaxVal, X->getType()); + Value *BoundsCheck = Builder.CreateICmp(ICmpInst::ICMP_ULT, X, MaxVal); + + // %trunc = trunc %srl to i1 + // Only care about the low bit + Value *ShrTrunc = Builder.CreateTrunc(LShr, IntegerType::get(Context, 1)); + + // %sel = select %icmp, %trunc, false + return Builder.CreateSelect(BoundsCheck, ShrTrunc, + ConstantInt::getFalse(Context)); + }; + + // Our BitMap should be able to fit into a single arch register + // otherwise the tranformation won't be profitable + unsigned XLen = DL.getLargestLegalIntTypeSizeInBits(); + auto validImm = [&](APInt APImm) -> bool { + auto Imm = APImm.tryZExtValue(); + return Imm && (*Imm < XLen); + }; + + // Match (or (icmp eq X, Imm0), (icmp eq X, Imm1)) + ConstantInt *LHS, *RHS; + Value *X = nullptr; + if (isICmpEqImm(Or.getOperand(0), LHS, X) && + isICmpEqImm(Or.getOperand(1), RHS, X)) { + // The Shr with become poison when shifted by Undef + if (!isGuaranteedNotToBeUndefOrPoison(X)) + return nullptr; + + APInt LHSAP = LHS->getValue(); + APInt RHSAP = RHS->getValue(); + if (!validImm(LHSAP) || !validImm(RHSAP)) + return nullptr; + LHSAP = LHSAP.zextOrTrunc(XLen); + RHSAP = RHSAP.zextOrTrunc(XLen); + + // Create the BitMap and Bounds check immediates + // +1 to bound becuase strictly less than + APInt BitMap = (APInt(XLen, 1) << LHSAP) | (APInt(XLen, 1) << RHSAP); + APInt Bound = RHSAP.ugt(LHSAP) ? RHSAP : LHSAP; + return CreateBitExtractSeq(BitMap, Bound + 1, X); + } + + // Expand an already existing BitMap sequence + // Match: (or (%BitMapSeq(X)), (icmp eq X, Imm)) + ConstantInt *BitMap, *Bound, *CmpImm; + Value *Cmp; + if (match(&Or, m_OneUse(m_c_Or(m_Value(Cmp), + m_OneUse(m_Select( + m_SpecificICmp(ICmpInst::ICMP_ULT, + m_ZExtOrSelf(m_Value(X)), + m_ConstantInt(Bound)), + m_OneUse(m_Trunc(m_OneUse(m_Shr( + m_ConstantInt(BitMap), + m_ZExtOrTruncOrSelf(m_Deferred(X)))))), + m_Zero()))))) && + isICmpEqImm(Cmp, CmpImm, X)) { + if (!isGuaranteedNotToBeUndefOrPoison(X)) + return nullptr; + + APInt NewAP = CmpImm->getValue(); + APInt BitMapAP = BitMap->getValue(); + APInt BoundAP = Bound->getValue().zextOrTrunc(XLen); + // BitMap must fit in native arch register + if (!validImm(NewAP) || !DL.fitsInLegalInteger(BitMapAP.getActiveBits())) + return nullptr; + + NewAP = NewAP.zextOrTrunc(XLen); + BitMapAP = BitMapAP.zextOrTrunc(XLen); + + // Bounding immediate must be greater than the largest bit in the BitMap + // and less then XLen + if (BoundAP.ult(BitMapAP.getActiveBits()) || BoundAP.ugt(XLen)) + return nullptr; + + if (NewAP.uge(BoundAP)) + BoundAP = NewAP + 1; + BitMapAP |= (APInt(XLen, 1) << NewAP); + return CreateBitExtractSeq(BitMapAP, BoundAP, X); + } + return nullptr; +} + /// Attempt to combine or(zext(x),shl(zext(y),bw/2) concat packing patterns. static Value *matchOrConcat(Instruction &Or, InstCombiner::BuilderTy &Builder) { assert(Or.getOpcode() == Instruction::Or && "bswap requires an 'or'"); @@ -4084,6 +4205,10 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) { if (Instruction *Funnel = matchFunnelShift(I, *this)) return Funnel; + if (Value *BitExtract = + combineOrOfImmCmpToBitExtract(I, Builder, getDataLayout())) + return replaceInstUsesWith(I, BitExtract); + if (Value *Concat = matchOrConcat(I, Builder)) return replaceInstUsesWith(I, Concat); diff --git a/llvm/test/Transforms/InstCombine/flag_check.ll b/llvm/test/Transforms/InstCombine/flag_check.ll new file mode 100644 index 0000000000000..ccf150c311f8d --- /dev/null +++ b/llvm/test/Transforms/InstCombine/flag_check.ll @@ -0,0 +1,360 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +target datalayout = "n32:64" + +define i1 @or_icmp_2(i32 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_2( +; CHECK-SAME: i32 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = zext nneg i32 [[TYPE]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 65, [[TMP0]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TYPE]], 7 +; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[TMP1]] to i1 +; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[TMP2]], i1 [[TMP3]], i1 false +; CHECK-NEXT: ret i1 [[OR_COND]] +; +entry: + %cmp = icmp eq i32 %type, 6 + %cmp1 = icmp eq i32 %type, 0 + %or.cond = or i1 %cmp, %cmp1 + ret i1 %or.cond +} + +define i1 @or_icmp_3(i32 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_3( +; CHECK-SAME: i32 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = zext nneg i32 [[TYPE]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 32833, [[TMP0]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TYPE]], 16 +; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[TMP1]] to i1 +; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[TMP2]], i1 [[TMP3]], i1 false +; CHECK-NEXT: ret i1 [[OR_COND]] +; +entry: + %cmp = icmp eq i32 %type, 6 + %cmp1 = icmp eq i32 %type, 0 + %or.cond = or i1 %cmp, %cmp1 + %cmp2 = icmp eq i32 %type, 15 + %or.cond1 = or i1 %cmp2, %or.cond + ret i1 %or.cond1 +} + +define i1 @or_icmp_7(i32 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_7( +; CHECK-SAME: i32 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = zext nneg i32 [[TYPE]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 2416066633, [[TMP0]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TYPE]], 32 +; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[TMP1]] to i1 +; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[TMP2]], i1 [[TMP3]], i1 false +; CHECK-NEXT: ret i1 [[OR_COND]] +; +entry: + %cmp = icmp eq i32 %type, 6 + %cmp1 = icmp eq i32 %type, 0 + %or.cond = or i1 %cmp, %cmp1 + %cmp2 = icmp eq i32 %type, 17 + %or.cond1 = or i1 %cmp2, %or.cond + %cmp3 = icmp eq i32 %type, 3 + %or.cond2 = or i1 %cmp3, %or.cond1 + %cmp4 = icmp eq i32 %type, 31 + %or.cond3 = or i1 %cmp4, %or.cond2 + %cmp5 = icmp eq i32 %type, 14 + %or.cond4 = or i1 %cmp5, %or.cond3 + %cmp6 = icmp eq i32 %type, 28 + %or.cond5 = or i1 %cmp6, %or.cond4 + ret i1 %or.cond5 +} + +; Cannot optimize since Imm > XLen +define i1 @or_icmp_gte_64(i32 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_gte_64( +; CHECK-SAME: i32 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TYPE]], 6 +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TYPE]], 64 +; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[CMP]], [[CMP1]] +; CHECK-NEXT: ret i1 [[OR_COND]] +; +entry: + %cmp = icmp eq i32 %type, 6 + %cmp1 = icmp eq i32 %type, 64 + %or.cond = or i1 %cmp, %cmp1 + ret i1 %or.cond +} + +; Cannot optimize since %type has multiple uses +define i32 @or_icmp_multiple_uses(i32 signext noundef %type) { +; CHECK-LABEL: define i32 @or_icmp_multiple_uses( +; CHECK-SAME: i32 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TYPE]], 6 +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TYPE]], 0 +; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: [[CMP_EXT:%.*]] = zext i1 [[CMP1]] to i32 +; CHECK-NEXT: [[OR_COND_EXT:%.*]] = zext i1 [[OR_COND]] to i32 +; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[CMP_EXT]], [[OR_COND_EXT]] +; CHECK-NEXT: ret i32 [[ADD]] +; +entry: + %cmp = icmp eq i32 %type, 6 + %cmp1 = icmp eq i32 %type, 0 + %or.cond = or i1 %cmp, %cmp1 + %cmp.ext = zext i1 %cmp to i32 + %or.cond.ext = zext i1 %or.cond to i32 + %add = add i32 %cmp.ext, %or.cond.ext + ret i32 %add +} + +; Cannot optimize since not == comparison +define i1 @or_icmp_not_eq(i32 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_not_eq( +; CHECK-SAME: i32 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[TYPE]], -7 +; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[TMP0]], -5 +; CHECK-NEXT: ret i1 [[CMP1]] +; +entry: + %cmp = icmp ugt i32 %type, 6 + %cmp1 = icmp ult i32 %type, 2 + %or.cond = or i1 %cmp, %cmp1 + ret i1 %or.cond +} + +define i1 @or_icmp_i64(i64 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_i64( +; CHECK-SAME: i64 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = lshr i64 32833, [[TYPE]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TYPE]], 16 +; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[TMP0]] to i1 +; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[TMP1]], i1 [[TMP2]], i1 false +; CHECK-NEXT: ret i1 [[OR_COND]] +; +entry: + %cmp = icmp eq i64 %type, 6 + %cmp1 = icmp eq i64 %type, 0 + %or.cond = or i1 %cmp, %cmp1 + %cmp2 = icmp eq i64 %type, 15 + %or.cond1 = or i1 %cmp2, %or.cond + ret i1 %or.cond1 +} + +; Cannot optimize since not the same value being compared +define i1 @or_icmp_specific(i64 signext noundef %type, i64 signext noundef %type1, i64 signext noundef %type2) { +; CHECK-LABEL: define i1 @or_icmp_specific( +; CHECK-SAME: i64 noundef signext [[TYPE:%.*]], i64 noundef signext [[TYPE1:%.*]], i64 noundef signext [[TYPE2:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[TYPE]], 6 +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i64 [[TYPE1]], 0 +; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[CMP]], [[CMP1]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i64 [[TYPE]], 15 +; CHECK-NEXT: [[OR_COND1:%.*]] = or i1 [[CMP2]], [[OR_COND]] +; CHECK-NEXT: ret i1 [[OR_COND1]] +; +entry: + %cmp = icmp eq i64 %type, 6 + %cmp1 = icmp eq i64 %type1, 0 + %or.cond = or i1 %cmp, %cmp1 + %cmp2 = icmp eq i64 %type, 15 + %or.cond1 = or i1 %cmp2, %or.cond + ret i1 %or.cond1 +} + +; Cannot optimize since %type can be un-def +define i1 @or_icmp_undef(i64 signext %type) { +; CHECK-LABEL: define i1 @or_icmp_undef( +; CHECK-SAME: i64 signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[TYPE]], 6 +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i64 [[TYPE]], 0 +; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[CMP]], [[CMP1]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i64 [[TYPE]], 15 +; CHECK-NEXT: [[OR_COND1:%.*]] = or i1 [[CMP2]], [[OR_COND]] +; CHECK-NEXT: ret i1 [[OR_COND1]] +; +entry: + %cmp = icmp eq i64 %type, 6 + %cmp1 = icmp eq i64 %type, 0 + %or.cond = or i1 %cmp, %cmp1 + %cmp2 = icmp eq i64 %type, 15 + %or.cond1 = or i1 %cmp2, %or.cond + ret i1 %or.cond1 +} + +define i1 @or_icmp_expand(i64 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_expand( +; CHECK-SAME: i64 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[SHR:%.*]] = lshr i64 34359738433, [[TYPE]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[TYPE]], 36 +; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[SHR]] to i1 +; CHECK-NEXT: [[AND:%.*]] = select i1 [[CMP]], i1 [[TRUNC]], i1 false +; CHECK-NEXT: ret i1 [[AND]] +; +entry: + %shr = lshr i64 65, %type + %cmp = icmp ult i64 %type, 7 + %trunc = trunc i64 %shr to i1 + %and = select i1 %cmp, i1 %trunc, i1 false + %cmp1 = icmp eq i64 %type, 35 + %or.cond = or i1 %and, %cmp1 + ret i1 %or.cond +} + +; Cannot optimize bounds check smaller than largest BitMap bit +define i1 @or_icmp_expand_small_bounds(i64 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_expand_small_bounds( +; CHECK-SAME: i64 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[SHR:%.*]] = lshr i64 65, [[TYPE]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[TYPE]], 3 +; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[SHR]] to i1 +; CHECK-NEXT: [[AND:%.*]] = select i1 [[CMP]], i1 [[TRUNC]], i1 false +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i64 [[TYPE]], 35 +; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[AND]], [[CMP1]] +; CHECK-NEXT: ret i1 [[OR_COND]] +; +entry: + %shr = lshr i64 65, %type + %cmp = icmp ult i64 %type, 3 + %trunc = trunc i64 %shr to i1 + %and = select i1 %cmp, i1 %trunc, i1 false + %cmp1 = icmp eq i64 %type, 35 + %or.cond = or i1 %and, %cmp1 + ret i1 %or.cond +} + +; Cannot optimize bounds check larger than XLen +define i1 @or_icmp_expand_large_bounds(i64 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_expand_large_bounds( +; CHECK-SAME: i64 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[SHR:%.*]] = lshr i64 65, [[TYPE]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[TYPE]], 65 +; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[SHR]] to i1 +; CHECK-NEXT: [[AND:%.*]] = select i1 [[CMP]], i1 [[TRUNC]], i1 false +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i64 [[TYPE]], 35 +; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[AND]], [[CMP1]] +; CHECK-NEXT: ret i1 [[OR_COND]] +; +entry: + %shr = lshr i64 65, %type + %cmp = icmp ult i64 %type, 65 + %trunc = trunc i64 %shr to i1 + %and = select i1 %cmp, i1 %trunc, i1 false + %cmp1 = icmp eq i64 %type, 35 + %or.cond = or i1 %and, %cmp1 + ret i1 %or.cond +} + +define i1 @or_icmp_expand_trunc_type_shr(i128 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_expand_trunc_type_shr( +; CHECK-SAME: i128 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = trunc i128 [[TYPE]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 34359738433, [[TMP0]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i128 [[TYPE]], 64 +; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[TMP1]] to i1 +; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[TMP2]], i1 [[TMP3]], i1 false +; CHECK-NEXT: ret i1 [[OR_COND]] +; +entry: + %type.t = trunc i128 %type to i64 + %shr = lshr i64 65, %type.t + %cmp = icmp ult i128 %type, 64 + %trunc = trunc i64 %shr to i1 + %and = select i1 %cmp, i1 %trunc, i1 false + %cmp1 = icmp eq i128 %type, 35 + %or.cond = or i1 %and, %cmp1 + ret i1 %or.cond +} + +define i1 @or_icmp_expand_zext_cmp(i64 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_expand_zext_cmp( +; CHECK-SAME: i64 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = lshr i64 34359738433, [[TYPE]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TYPE]], 64 +; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[TMP0]] to i1 +; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[TMP1]], i1 [[TMP2]], i1 false +; CHECK-NEXT: ret i1 [[OR_COND]] +; +entry: + %type.e = zext i64 %type to i128 + %shr = lshr i64 65, %type + %cmp = icmp ult i128 %type.e, 64 + %trunc = trunc i64 %shr to i1 + %and = select i1 %cmp, i1 %trunc, i1 false + %cmp1 = icmp eq i64 %type, 35 + %or.cond = or i1 %and, %cmp1 + ret i1 %or.cond +} + +define i1 @or_icmp_i128(i128 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_i128( +; CHECK-SAME: i128 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = trunc i128 [[TYPE]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 32833, [[TMP0]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i128 [[TYPE]], 16 +; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[TMP1]] to i1 +; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[TMP2]], i1 [[TMP3]], i1 false +; CHECK-NEXT: ret i1 [[OR_COND]] +; +entry: + %cmp = icmp eq i128 %type, 6 + %cmp1 = icmp eq i128 %type, 0 + %or.cond = or i1 %cmp, %cmp1 + %cmp2 = icmp eq i128 %type, 15 + %or.cond1 = or i1 %cmp2, %or.cond + ret i1 %or.cond1 +} + +define i1 @or_icmp_expand_128(i128 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_expand_128( +; CHECK-SAME: i128 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = trunc i128 [[TYPE]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 34359738433, [[TMP0]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i128 [[TYPE]], 64 +; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[TMP1]] to i1 +; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[TMP2]], i1 [[TMP3]], i1 false +; CHECK-NEXT: ret i1 [[OR_COND]] +; +entry: + %shr = lshr i128 65, %type + %cmp = icmp ult i128 %type, 64 + %trunc = trunc i128 %shr to i1 + %and = select i1 %cmp, i1 %trunc, i1 false + %cmp1 = icmp eq i128 %type, 35 + %or.cond = or i1 %and, %cmp1 + ret i1 %or.cond +} + +; Cannot optimize BitMap lrger than XLen +define i1 @or_icmp_expand_large_bitmap(i128 signext noundef %type) { +; CHECK-LABEL: define i1 @or_icmp_expand_large_bitmap( +; CHECK-SAME: i128 noundef signext [[TYPE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[SHR:%.*]] = lshr i128 73786976294838206465, [[TYPE]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i128 [[TYPE]], 64 +; CHECK-NEXT: [[TRUNC:%.*]] = trunc i128 [[SHR]] to i1 +; CHECK-NEXT: [[AND1:%.*]] = select i1 [[CMP]], i1 [[TRUNC]], i1 false +; CHECK-NEXT: [[AND:%.*]] = icmp eq i128 [[TYPE]], 35 +; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[AND1]], [[AND]] +; CHECK-NEXT: ret i1 [[OR_COND]] +; +entry: + %shr = lshr i128 73786976294838206465, %type + %cmp = icmp ult i128 %type, 64 + %trunc = trunc i128 %shr to i1 + %and = select i1 %cmp, i1 %trunc, i1 false + %cmp1 = icmp eq i128 %type, 35 + %or.cond = or i1 %and, %cmp1 + ret i1 %or.cond +}