diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp index 8eb33a3e53364..f94961bfe26d1 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp @@ -905,8 +905,32 @@ void VPlanTransforms::truncateToMinimalBitwidths( // type. Skip those here, after incrementing NumProcessedRecipes. Also // skip casts which do not need to be handled explicitly here, as // redundant casts will be removed during recipe simplification. - if (isa(&R)) + if (isa(&R)) { +#ifndef NDEBUG + // If any of the operands is a live-in and not used by VPWidenRecipe or + // VPWidenSelectRecipe, but in MinBWs, make sure it is counted as + // processed as well. When MinBWs is currently constructed, there is no + // information about whether recipes are widened or replicated and in + // case they are reciplicated the operands are not truncated. Counting + // them them here ensures we do not miss any recipes in MinBWs. + // TODO: Remove once the analysis is done on VPlan. + for (VPValue *Op : R.operands()) { + if (!Op->isLiveIn()) + continue; + auto *UV = dyn_cast_or_null(Op->getUnderlyingValue()); + if (UV && MinBWs.contains(UV) && !ProcessedTruncs.contains(Op) && + all_of(Op->users(), [](VPUser *U) { + return !isa(U); + })) { + // Add an entry to ProcessedTruncs to avoid counting the same + // operand multiple times. + ProcessedTruncs[Op] = nullptr; + NumProcessedRecipes += 1; + } + } +#endif continue; + } Type *OldResTy = TypeInfo.inferScalarType(ResultVPV); unsigned OldResSizeInBits = OldResTy->getScalarSizeInBits(); diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/deterministic-type-shrinkage.ll b/llvm/test/Transforms/LoopVectorize/AArch64/deterministic-type-shrinkage.ll index 20d87d3ecc27e..b8208e1abda94 100644 --- a/llvm/test/Transforms/LoopVectorize/AArch64/deterministic-type-shrinkage.ll +++ b/llvm/test/Transforms/LoopVectorize/AArch64/deterministic-type-shrinkage.ll @@ -383,3 +383,37 @@ loop: exit: ret void } + +; Test case for #74231. +define void @replicate_operands_in_with_operands_in_minbws(ptr %dst, ptr noalias %src.1, ptr noalias %src.2, i32 %x) { +entry: + %sub = sub i32 %x, 10 + br label %loop.header + +loop.header: + %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ] + %gep.src.1 = getelementptr inbounds i32, ptr %src.1, i64 %iv + %l = load i32, ptr %gep.src.1 + %c.1 = icmp eq i32 %l, 10 + br i1 %c.1, label %loop.latch, label %if.then + +if.then: + %gep.src.2 = getelementptr inbounds i16, ptr %src.2, i64 %iv + %l.2 = load i16, ptr %gep.src.2 + %c.2 = icmp ule i16 %l.2, 99 + %conv = zext i16 %l.2 to i32 + %sel = select i1 %c.2, i32 %sub, i32 %conv + %add = add i32 %conv, %sel + %trunc = trunc i32 %add to i16 + %gep.dst = getelementptr inbounds i32, ptr %dst, i64 %iv + store i16 %trunc, ptr %gep.dst, align 2 + br label %loop.latch + +loop.latch: + %iv.next = add i64 %iv, 1 + %tobool.not = icmp eq i64 %iv.next, 1000 + br i1 %tobool.not, label %exit, label %loop.header + +exit: + ret void +}