[llvm] [VPlan] Extend cse to eliminate redundant widened loads (PR #212543)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 30 03:59:28 PDT 2026


================
@@ -2304,16 +2308,51 @@ struct VPCSEDenseMapInfo : public DenseMapInfo<VPSingleDefRecipe *> {
 };
 } // end anonymous namespace
 
-/// Perform a common-subexpression-elimination of VPSingleDefRecipes on the \p
-/// Plan.
+/// Perform a common-subexpression-elimination of single-def recipes on the \p
+/// Plan, also eliminating redundant widened loads within a basic block.
 void VPlanTransforms::cse(VPlan &Plan) {
   VPDominatorTree VPDT(Plan);
   DenseMap<VPSingleDefRecipe *, VPSingleDefRecipe *, VPCSEDenseMapInfo> CSEMap;
 
   ReversePostOrderTraversal<VPBlockDeepTraversalWrapper<VPBlockBase *>> RPOT(
       Plan.getEntry());
   for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(RPOT)) {
-    for (VPRecipeBase &R : *VPBB) {
+    // Widened loads that can be reused within this block, cleared by any
+    // intervening store (see below).
+    SmallVector<VPWidenLoadRecipe *, 4> LoadCandidates;
+    for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
+      // A recipe that may write to memory could alias a candidate load, so
+      // conservatively drop all candidates: a later load must not be CSE'd to a
+      // value read before the write. This avoids needing alias analysis.
+      if (R.mayWriteToMemory())
+        LoadCandidates.clear();
+
+      // Widened loads are not handled by the map-based CSE below; match them
+      // against the per-block candidates instead, reusing an earlier load with
+      // the same address, mask, type and alignment.
+      if (auto *Load = dyn_cast<VPWidenLoadRecipe>(&R)) {
+        VPWidenLoadRecipe *Match = nullptr;
+        for (VPWidenLoadRecipe *C : LoadCandidates) {
+          // Consecutive vs. gather loads have different address operands, so
+          // the operand check below also distinguishes those cases.
+          if (C->getScalarType() != Load->getScalarType() ||
+              C->getAlign() != Load->getAlign() ||
+              !equal(C->operands(), Load->operands()))
+            continue;
+          Match = C;
+          break;
+        }
+        if (Match) {
+          // Keep only metadata common to both loads on the survivor.
+          Match->intersect(*Load);
----------------
fhahn wrote:

I think a test for this is missing

https://github.com/llvm/llvm-project/pull/212543


More information about the llvm-commits mailing list