[llvm] [VPlan] Introduce CSE pass (PR #151872)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 27 08:48:12 PDT 2025
================
@@ -1792,6 +1792,120 @@ void VPlanTransforms::clearReductionWrapFlags(VPlan &Plan) {
}
}
+namespace {
+struct VPCSEDenseMapInfo : public DenseMapInfo<VPSingleDefRecipe *> {
+ static bool isSentinel(const VPSingleDefRecipe *Def) {
+ return Def == getEmptyKey() || Def == getTombstoneKey();
+ }
+
+ /// Get any instruction opcode or intrinsic ID data embedded in recipe \p R.
+ /// Returns an optional pair, where the first element indicates whether it is
+ /// an intrinsic ID.
+ static std::optional<std::pair<bool, unsigned>>
+ getOpcodeOrIntrinsicID(const VPSingleDefRecipe *R) {
+ return TypeSwitch<const VPSingleDefRecipe *,
+ std::optional<std::pair<bool, unsigned>>>(R)
+ .Case<VPInstruction, VPWidenRecipe, VPWidenCastRecipe,
+ VPWidenSelectRecipe, VPHistogramRecipe, VPPartialReductionRecipe,
+ VPReplicateRecipe>(
+ [](auto *I) { return std::make_pair(false, I->getOpcode()); })
+ .Case<VPWidenIntrinsicRecipe>([](auto *I) {
+ return std::make_pair(true, I->getVectorIntrinsicID());
+ })
+ .Default([](auto *) { return std::nullopt; });
+ }
+
+ /// During CSE, we can only handle certain recipes that don't read from
+ /// memory: if they read from memory, there could be an intervening write to
+ /// memory before the next instance is CSE'd, leading to an incorrect result.
+ /// We can extend the list of handled recipes in the future, provided we
+ /// account for the data embedded in them while checking for equality or
+ /// hashing.
+ static bool canHandle(const VPSingleDefRecipe *Def) {
+ // The issue with (Insert|Extract)Value is that the index of the
+ // insert/extract is not a proper operand in LLVM IR, and hence also not in
+ // VPlan.
+ if (auto C = getOpcodeOrIntrinsicID(Def))
+ if (!C->first && (C->second == Instruction::InsertValue ||
+ C->second == Instruction::ExtractValue))
+ return false;
+ return isa<VPInstruction, VPWidenRecipe, VPWidenCastRecipe,
+ VPWidenSelectRecipe, VPReplicateRecipe, VPWidenIntrinsicRecipe>(
+ Def) &&
+ !Def->mayReadFromMemory();
+ }
+
+ /// Hash the underlying data of \p Def.
+ static unsigned getHashValue(const VPSingleDefRecipe *Def) {
+ const VPlan *Plan = Def->getParent()->getPlan();
+ VPTypeAnalysis TypeInfo(*Plan);
+ hash_code Result = hash_combine(
+ Def->getVPDefID(), getOpcodeOrIntrinsicID(Def),
+ TypeInfo.inferScalarType(Def), vputils::isSingleScalar(Def),
+ hash_combine_range(Def->operands()));
+ if (auto *RFlags = dyn_cast<VPRecipeWithIRFlags>(Def))
+ if (RFlags->hasPredicate())
+ return hash_combine(Result, RFlags->getPredicate());
+ return Result;
+ }
+
+ /// Check equality of underlying data of \p L and \p R.
+ static bool isEqual(const VPSingleDefRecipe *L, const VPSingleDefRecipe *R) {
+ if (isSentinel(L) || isSentinel(R))
+ return L == R;
+ if (L->getVPDefID() != R->getVPDefID() ||
+ getOpcodeOrIntrinsicID(L) != getOpcodeOrIntrinsicID(R) ||
+ vputils::isSingleScalar(L) != vputils::isSingleScalar(R) ||
+ !equal(L->operands(), R->operands()))
+ return false;
+ if (auto *LFlags = dyn_cast<VPRecipeWithIRFlags>(L))
+ if (LFlags->hasPredicate() &&
+ LFlags->getPredicate() !=
+ cast<VPRecipeWithIRFlags>(R)->getPredicate())
+ return false;
+ const VPlan *Plan = L->getParent()->getPlan();
+ VPTypeAnalysis TypeInfo(*Plan);
+ return TypeInfo.inferScalarType(L) == TypeInfo.inferScalarType(R);
+ }
+};
+} // end anonymous namespace
+
+/// Perform a common-subexpression-elimination of VPSingleDefRecipes on the \p
+/// Plan.
+void VPlanTransforms::cse(VPlan &Plan) {
+ VPRegionBlock *LoopRegion = Plan.getVectorLoopRegion();
+ if (!LoopRegion)
+ return;
+
+ auto VPBBsOutsideLoopRegion = VPBlockUtils::blocksOnly<VPBasicBlock>(
+ vp_depth_first_shallow(Plan.getEntry()));
+ auto VPBBsInsideLoopRegion = VPBlockUtils::blocksOnly<VPBasicBlock>(
+ vp_depth_first_shallow(LoopRegion->getEntry()));
+ VPDominatorTree VPDT(Plan);
+
+ // Don't CSE in replicate regions.
----------------
artagnon wrote:
I think, somewhere along the development, there were regressions, but it seems that there are no changes now: fixed, thanks!
https://github.com/llvm/llvm-project/pull/151872
More information about the llvm-commits
mailing list