[llvm] UTC: support debug output from LDist (PR #93208)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 25 14:15:07 PDT 2024


https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/93208

>From 7fa14d469a3d4847a10890d988a7dda94ed5fa0e Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <r at artagnon.com>
Date: Thu, 23 May 2024 16:33:20 +0100
Subject: [PATCH] [UTC] support debug output from LDist

Tweak the LoopDistribute debug output to be stable, and extend
update_analyze_test_checks.py trivially to support this output.
---
 llvm/lib/Transforms/Scalar/LoopDistribute.cpp |  58 ++++-----
 .../Transforms/LoopDistribute/debug-print.ll  |  94 ++++++++++++--
 .../Inputs/loop-distribute.ll                 |  27 ++++
 .../Inputs/loop-distribute.ll.expected        | 118 ++++++++++++++++++
 .../loop-distribute.test                      |   6 +
 llvm/utils/UpdateTestChecks/common.py         |   6 +-
 llvm/utils/update_analyze_test_checks.py      |  10 +-
 7 files changed, 273 insertions(+), 46 deletions(-)
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_analyze_test_checks/Inputs/loop-distribute.ll
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_analyze_test_checks/Inputs/loop-distribute.ll.expected
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_analyze_test_checks/loop-distribute.test

diff --git a/llvm/lib/Transforms/Scalar/LoopDistribute.cpp b/llvm/lib/Transforms/Scalar/LoopDistribute.cpp
index 7a34ec2c008ccc..d2fed11fe509f8 100644
--- a/llvm/lib/Transforms/Scalar/LoopDistribute.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDistribute.cpp
@@ -26,7 +26,7 @@
 #include "llvm/ADT/DepthFirstIterator.h"
 #include "llvm/ADT/EquivalenceClasses.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/StringRef.h"
@@ -120,7 +120,7 @@ namespace {
 /// Maintains the set of instructions of the loop for a partition before
 /// cloning.  After cloning, it hosts the new loop.
 class InstPartition {
-  using InstructionSet = SmallPtrSet<Instruction *, 8>;
+  using InstructionSet = SetVector<Instruction *>;
 
 public:
   InstPartition(Instruction *I, Loop *L, bool DepCycle = false)
@@ -166,7 +166,7 @@ class InstPartition {
       // Insert instructions from the loop that we depend on.
       for (Value *V : I->operand_values()) {
         auto *I = dyn_cast<Instruction>(V);
-        if (I && OrigLoop->contains(I->getParent()) && Set.insert(I).second)
+        if (I && OrigLoop->contains(I->getParent()) && Set.insert(I))
           Worklist.push_back(I);
       }
     }
@@ -231,17 +231,16 @@ class InstPartition {
     }
   }
 
-  void print() const {
-    if (DepCycle)
-      dbgs() << "  (cycle)\n";
+  void print(raw_ostream &OS) const {
+    OS << (DepCycle ? " (cycle)\n" : "\n");
     for (auto *I : Set)
       // Prefix with the block name.
-      dbgs() << "  " << I->getParent()->getName() << ":" << *I << "\n";
+      OS << "  " << I->getParent()->getName() << ":" << *I << "\n";
   }
 
-  void printBlocks() const {
+  void printBlocks(raw_ostream &OS) const {
     for (auto *BB : getDistributedLoop()->getBlocks())
-      dbgs() << *BB;
+      OS << *BB;
   }
 
 private:
@@ -368,11 +367,11 @@ class InstPartitionContainer {
           std::tie(LoadToPart, NewElt) =
               LoadToPartition.insert(std::make_pair(Inst, PartI));
           if (!NewElt) {
-            LLVM_DEBUG(dbgs()
-                       << "Merging partitions due to this load in multiple "
-                       << "partitions: " << PartI << ", " << LoadToPart->second
-                       << "\n"
-                       << *Inst << "\n");
+            LLVM_DEBUG(
+                dbgs()
+                << "LDist: Merging partitions due to this load in multiple "
+                << "partitions: " << PartI << ", " << LoadToPart->second << "\n"
+                << *Inst << "\n");
 
             auto PartJ = I;
             do {
@@ -530,8 +529,8 @@ class InstPartitionContainer {
   void print(raw_ostream &OS) const {
     unsigned Index = 0;
     for (const auto &P : PartitionContainer) {
-      OS << "Partition " << Index++ << " (" << &P << "):\n";
-      P.print();
+      OS << "LDist: Partition " << Index++ << ":";
+      P.print(OS);
     }
   }
 
@@ -545,11 +544,11 @@ class InstPartitionContainer {
   }
 #endif
 
-  void printBlocks() const {
+  void printBlocks(raw_ostream &OS) const {
     unsigned Index = 0;
     for (const auto &P : PartitionContainer) {
-      dbgs() << "\nPartition " << Index++ << " (" << &P << "):\n";
-      P.printBlocks();
+      OS << "LDist: Partition " << Index++ << ":";
+      P.printBlocks(OS);
     }
   }
 
@@ -628,7 +627,7 @@ class MemoryInstructionDependences {
       const SmallVectorImpl<Dependence> &Dependences) {
     Accesses.append(Instructions.begin(), Instructions.end());
 
-    LLVM_DEBUG(dbgs() << "Backward dependences:\n");
+    LLVM_DEBUG(dbgs() << "LDist: Backward dependences:\n");
     for (const auto &Dep : Dependences)
       if (Dep.isPossiblyBackward()) {
         // Note that the designations source and destination follow the program
@@ -738,7 +737,7 @@ class LoopDistributeForLoop {
     for (auto *Inst : DefsUsedOutside)
       Partitions.addToNewNonCyclicPartition(Inst);
 
-    LLVM_DEBUG(dbgs() << "Seeded partitions:\n" << Partitions);
+    LLVM_DEBUG(dbgs() << "LDist: Seeded partitions:\n" << Partitions);
     if (Partitions.getSize() < 2)
       return fail("CantIsolateUnsafeDeps",
                   "cannot isolate unsafe dependencies");
@@ -746,19 +745,19 @@ class LoopDistributeForLoop {
     // Run the merge heuristics: Merge non-cyclic adjacent partitions since we
     // should be able to vectorize these together.
     Partitions.mergeBeforePopulating();
-    LLVM_DEBUG(dbgs() << "\nMerged partitions:\n" << Partitions);
+    LLVM_DEBUG(dbgs() << "LDist: Merged partitions:\n" << Partitions);
     if (Partitions.getSize() < 2)
       return fail("CantIsolateUnsafeDeps",
                   "cannot isolate unsafe dependencies");
 
     // Now, populate the partitions with non-memory operations.
     Partitions.populateUsedSet();
-    LLVM_DEBUG(dbgs() << "\nPopulated partitions:\n" << Partitions);
+    LLVM_DEBUG(dbgs() << "LDist: Populated partitions:\n" << Partitions);
 
     // In order to preserve original lexical order for loads, keep them in the
     // partition that we set up in the MemoryInstructionDependences loop.
     if (Partitions.mergeToAvoidDuplicatedLoads()) {
-      LLVM_DEBUG(dbgs() << "\nPartitions merged to ensure unique loads:\n"
+      LLVM_DEBUG(dbgs() << "LDist: Partitions merged to ensure unique loads:\n"
                         << Partitions);
       if (Partitions.getSize() < 2)
         return fail("CantIsolateUnsafeDeps",
@@ -782,7 +781,8 @@ class LoopDistributeForLoop {
     if (!IsForced.value_or(false) && hasDisableAllTransformsHint(L))
       return fail("HeuristicDisabled", "distribution heuristic disabled");
 
-    LLVM_DEBUG(dbgs() << "\nDistributing loop: " << *L << "\n");
+    LLVM_DEBUG(dbgs() << "LDist: Distributing loop: "
+                      << L->getHeader()->getName() << "\n");
     // We're done forming the partitions set up the reverse mapping from
     // instructions to partitions.
     Partitions.setupPartitionIdOnInstructions();
@@ -810,7 +810,7 @@ class LoopDistributeForLoop {
 
       MDNode *OrigLoopID = L->getLoopID();
 
-      LLVM_DEBUG(dbgs() << "\nPointers:\n");
+      LLVM_DEBUG(dbgs() << "LDist: Pointers:\n");
       LLVM_DEBUG(LAI->getRuntimePointerChecking()->printChecks(dbgs(), Checks));
       LoopVersioning LVer(*LAI, Checks, L, LI, DT, SE);
       LVer.versionLoop(DefsUsedOutside);
@@ -833,8 +833,8 @@ class LoopDistributeForLoop {
     // Now, we remove the instruction from each loop that don't belong to that
     // partition.
     Partitions.removeUnusedInsts();
-    LLVM_DEBUG(dbgs() << "\nAfter removing unused Instrs:\n");
-    LLVM_DEBUG(Partitions.printBlocks());
+    LLVM_DEBUG(dbgs() << "LDist: After removing unused Instrs:\n");
+    LLVM_DEBUG(Partitions.printBlocks(dbgs()));
 
     if (LDistVerify) {
       LI->verify(*DT);
@@ -856,7 +856,7 @@ class LoopDistributeForLoop {
     LLVMContext &Ctx = F->getContext();
     bool Forced = isForced().value_or(false);
 
-    LLVM_DEBUG(dbgs() << "Skipping; " << Message << "\n");
+    LLVM_DEBUG(dbgs() << "LDist: Skipping; " << Message << "\n");
 
     // With Rpass-missed report that distribution failed.
     ORE->emit([&]() {
diff --git a/llvm/test/Transforms/LoopDistribute/debug-print.ll b/llvm/test/Transforms/LoopDistribute/debug-print.ll
index 733c33483ecc40..2c3a0116fe1315 100644
--- a/llvm/test/Transforms/LoopDistribute/debug-print.ll
+++ b/llvm/test/Transforms/LoopDistribute/debug-print.ll
@@ -1,20 +1,92 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5
 ; REQUIRES: asserts
 ; RUN: opt -passes=loop-distribute -enable-loop-distribute \
 ; RUN:   -debug-only=loop-distribute -disable-output 2>&1 %s | FileCheck %s
 
 define void @f(ptr noalias %a, ptr noalias %b, ptr noalias %c, ptr noalias %d, i64 %stride) {
 ; CHECK-LABEL: 'f'
-; CHECK:        LDist: Found a candidate loop: for.body
-; CHECK:        Backward dependences:
-; CHECK-NEXT:     Backward:
-; CHECK-NEXT:         %load.a = load i32, ptr %gep.a, align 4 ->
-; CHECK-NEXT:         store i32 %mul.a, ptr %gep.a.plus4, align 4
-; CHECK:        Seeded partitions:
-; CHECK:        Partition 0
-; CHECK:        Partition 1
-; CHECK:        Partition 2
-; CHECK:        Partition 3
-; CHECK:        Distributing loop
+; CHECK-NEXT:  LDist: Found a candidate loop: for.body
+; CHECK-NEXT:  LDist: Backward dependences:
+; CHECK-NEXT:    Backward:
+; CHECK-NEXT:        %load.a = load i32, ptr %gep.a, align 4 ->
+; CHECK-NEXT:        store i32 %mul.a, ptr %gep.a.plus4, align 4
+; CHECK-NEXT:  LDist: Seeded partitions:
+; CHECK-NEXT:  LDist: Partition 0: (cycle)
+; CHECK-NEXT:    for.body: %load.a = load i32, ptr %gep.a, align 4
+; CHECK-NEXT:    for.body: %load.b = load i32, ptr %gep.b, align 4
+; CHECK-NEXT:    for.body: store i32 %mul.a, ptr %gep.a.plus4, align 4
+; CHECK-NEXT:  LDist: Partition 1:
+; CHECK-NEXT:    for.body: %loadD = load i32, ptr %gep.d, align 4
+; CHECK-NEXT:  LDist: Partition 2:
+; CHECK-NEXT:    for.body: %load.strided.a = load i32, ptr %gep.strided.a, align 4
+; CHECK-NEXT:  LDist: Partition 3:
+; CHECK-NEXT:    for.body: store i32 %mul.c, ptr %gep.c, align 4
+; CHECK-NEXT:  LDist: Merged partitions:
+; CHECK-NEXT:  LDist: Partition 0: (cycle)
+; CHECK-NEXT:    for.body: %load.a = load i32, ptr %gep.a, align 4
+; CHECK-NEXT:    for.body: %load.b = load i32, ptr %gep.b, align 4
+; CHECK-NEXT:    for.body: store i32 %mul.a, ptr %gep.a.plus4, align 4
+; CHECK-NEXT:  LDist: Partition 1:
+; CHECK-NEXT:    for.body: %loadD = load i32, ptr %gep.d, align 4
+; CHECK-NEXT:    for.body: %load.strided.a = load i32, ptr %gep.strided.a, align 4
+; CHECK-NEXT:    for.body: store i32 %mul.c, ptr %gep.c, align 4
+; CHECK-NEXT:  LDist: Populated partitions:
+; CHECK-NEXT:  LDist: Partition 0: (cycle)
+; CHECK-NEXT:    for.body: %load.a = load i32, ptr %gep.a, align 4
+; CHECK-NEXT:    for.body: %load.b = load i32, ptr %gep.b, align 4
+; CHECK-NEXT:    for.body: store i32 %mul.a, ptr %gep.a.plus4, align 4
+; CHECK-NEXT:    for.body: br i1 %exitcond, label %exit, label %for.body
+; CHECK-NEXT:    for.body: %exitcond = icmp eq i64 %add, 20
+; CHECK-NEXT:    for.body: %add = add nuw nsw i64 %ind, 1
+; CHECK-NEXT:    for.body: %ind = phi i64 [ 0, %entry ], [ %add, %for.body ]
+; CHECK-NEXT:    for.body: %mul.a = mul i32 %load.b, %load.a
+; CHECK-NEXT:    for.body: %gep.a.plus4 = getelementptr inbounds i32, ptr %a, i64 %add
+; CHECK-NEXT:    for.body: %gep.b = getelementptr inbounds i32, ptr %b, i64 %ind
+; CHECK-NEXT:    for.body: %gep.a = getelementptr inbounds i32, ptr %a, i64 %ind
+; CHECK-NEXT:  LDist: Partition 1:
+; CHECK-NEXT:    for.body: %loadD = load i32, ptr %gep.d, align 4
+; CHECK-NEXT:    for.body: %load.strided.a = load i32, ptr %gep.strided.a, align 4
+; CHECK-NEXT:    for.body: store i32 %mul.c, ptr %gep.c, align 4
+; CHECK-NEXT:    for.body: br i1 %exitcond, label %exit, label %for.body
+; CHECK-NEXT:    for.body: %exitcond = icmp eq i64 %add, 20
+; CHECK-NEXT:    for.body: %add = add nuw nsw i64 %ind, 1
+; CHECK-NEXT:    for.body: %ind = phi i64 [ 0, %entry ], [ %add, %for.body ]
+; CHECK-NEXT:    for.body: %mul.c = mul i32 %loadD, %load.strided.a
+; CHECK-NEXT:    for.body: %gep.c = getelementptr inbounds i32, ptr %c, i64 %ind
+; CHECK-NEXT:    for.body: %gep.strided.a = getelementptr inbounds i32, ptr %a, i64 %mul
+; CHECK-NEXT:    for.body: %mul = mul i64 %ind, %stride
+; CHECK-NEXT:    for.body: %gep.d = getelementptr inbounds i32, ptr %d, i64 %ind
+; CHECK-NEXT:  LDist: Distributing loop: for.body
+; CHECK-NEXT:  LDist: Pointers:
+; CHECK-NEXT:  LDist: After removing unused Instrs:
+; CHECK-NEXT:  LDist: Partition 0:
+; CHECK-NEXT:  for.body.ldist1: ; preds = %for.body.ldist1, %for.body.ph.ldist1
+; CHECK-NEXT:    %ind.ldist1 = phi i64 [ 0, %for.body.ph.ldist1 ], [ %add.ldist1, %for.body.ldist1 ]
+; CHECK-NEXT:    %gep.a.ldist1 = getelementptr inbounds i32, ptr %a, i64 %ind.ldist1
+; CHECK-NEXT:    %load.a.ldist1 = load i32, ptr %gep.a.ldist1, align 4
+; CHECK-NEXT:    %gep.b.ldist1 = getelementptr inbounds i32, ptr %b, i64 %ind.ldist1
+; CHECK-NEXT:    %load.b.ldist1 = load i32, ptr %gep.b.ldist1, align 4
+; CHECK-NEXT:    %mul.a.ldist1 = mul i32 %load.b.ldist1, %load.a.ldist1
+; CHECK-NEXT:    %add.ldist1 = add nuw nsw i64 %ind.ldist1, 1
+; CHECK-NEXT:    %gep.a.plus4.ldist1 = getelementptr inbounds i32, ptr %a, i64 %add.ldist1
+; CHECK-NEXT:    store i32 %mul.a.ldist1, ptr %gep.a.plus4.ldist1, align 4
+; CHECK-NEXT:    %exitcond.ldist1 = icmp eq i64 %add.ldist1, 20
+; CHECK-NEXT:    br i1 %exitcond.ldist1, label %for.body.ph, label %for.body.ldist1
+; CHECK-NEXT:  LDist: Partition 1:
+; CHECK-NEXT:  for.body: ; preds = %for.body, %for.body.ph
+; CHECK-NEXT:    %ind = phi i64 [ 0, %for.body.ph ], [ %add, %for.body ]
+; CHECK-NEXT:    %add = add nuw nsw i64 %ind, 1
+; CHECK-NEXT:    %gep.d = getelementptr inbounds i32, ptr %d, i64 %ind
+; CHECK-NEXT:    %loadD = load i32, ptr %gep.d, align 4
+; CHECK-NEXT:    %mul = mul i64 %ind, %stride
+; CHECK-NEXT:    %gep.strided.a = getelementptr inbounds i32, ptr %a, i64 %mul
+; CHECK-NEXT:    %load.strided.a = load i32, ptr %gep.strided.a, align 4
+; CHECK-NEXT:    %mul.c = mul i32 %loadD, %load.strided.a
+; CHECK-NEXT:    %gep.c = getelementptr inbounds i32, ptr %c, i64 %ind
+; CHECK-NEXT:    store i32 %mul.c, ptr %gep.c, align 4
+; CHECK-NEXT:    %exitcond = icmp eq i64 %add, 20
+; CHECK-NEXT:    br i1 %exitcond, label %exit.loopexit1, label %for.body
+;
 entry:
   br label %for.body
 
diff --git a/llvm/test/tools/UpdateTestChecks/update_analyze_test_checks/Inputs/loop-distribute.ll b/llvm/test/tools/UpdateTestChecks/update_analyze_test_checks/Inputs/loop-distribute.ll
new file mode 100644
index 00000000000000..48f80533c6379b
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_analyze_test_checks/Inputs/loop-distribute.ll
@@ -0,0 +1,27 @@
+; RUN: opt -passes=loop-distribute -enable-loop-distribute \
+; RUN:   -debug-only=loop-distribute -disable-output 2>&1 %s | FileCheck %s
+
+define void @ldist(i1 %c, ptr %A, ptr %B, ptr %C) {
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %if.end, %entry
+  %iv = phi i16 [ 0, %entry ], [ %iv.next, %if.end ]
+  %lv = load i16, ptr %A, align 1
+  store i16 %lv, ptr %A, align 1
+  br i1 %c, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %lv2 = load i16, ptr %A, align 1
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  %c.sink = phi ptr [ %B, %if.then ], [ %C, %for.body ]
+  %lv3 = load i16, ptr %c.sink
+  %iv.next = add nuw nsw i16 %iv, 1
+  %tobool.not = icmp eq i16 %iv.next, 1000
+  br i1 %tobool.not, label %for.end.loopexit, label %for.body
+
+for.end.loopexit:                                 ; preds = %if.end
+  ret void
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_analyze_test_checks/Inputs/loop-distribute.ll.expected b/llvm/test/tools/UpdateTestChecks/update_analyze_test_checks/Inputs/loop-distribute.ll.expected
new file mode 100644
index 00000000000000..baef851b84ee54
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_analyze_test_checks/Inputs/loop-distribute.ll.expected
@@ -0,0 +1,118 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py
+; RUN: opt -passes=loop-distribute -enable-loop-distribute \
+; RUN:   -debug-only=loop-distribute -disable-output 2>&1 %s | FileCheck %s
+
+define void @ldist(i1 %c, ptr %A, ptr %B, ptr %C) {
+; CHECK-LABEL: 'ldist'
+; CHECK-NEXT:  LDist: Found a candidate loop: for.body
+; CHECK-NEXT:  LDist: Backward dependences:
+; CHECK-NEXT:    Unknown:
+; CHECK-NEXT:        %lv = load i16, ptr %A, align 1 ->
+; CHECK-NEXT:        store i16 %lv, ptr %A, align 1
+; CHECK-NEXT:    Unknown:
+; CHECK-NEXT:        store i16 %lv, ptr %A, align 1 ->
+; CHECK-NEXT:        %lv2 = load i16, ptr %A, align 1
+; CHECK-NEXT:  LDist: Seeded partitions:
+; CHECK-NEXT:  LDist: Partition 0: (cycle)
+; CHECK-NEXT:    for.body: %lv = load i16, ptr %A, align 1
+; CHECK-NEXT:    for.body: store i16 %lv, ptr %A, align 1
+; CHECK-NEXT:    if.then: %lv2 = load i16, ptr %A, align 1
+; CHECK-NEXT:  LDist: Partition 1:
+; CHECK-NEXT:    if.end: %lv3 = load i16, ptr %c.sink, align 2
+; CHECK-NEXT:  LDist: Partition 2:
+; CHECK-NEXT:    if.end: %lv3 = load i16, ptr %c.sink, align 2
+; CHECK-NEXT:  LDist: Merged partitions:
+; CHECK-NEXT:  LDist: Partition 0: (cycle)
+; CHECK-NEXT:    for.body: %lv = load i16, ptr %A, align 1
+; CHECK-NEXT:    for.body: store i16 %lv, ptr %A, align 1
+; CHECK-NEXT:    if.then: %lv2 = load i16, ptr %A, align 1
+; CHECK-NEXT:  LDist: Partition 1:
+; CHECK-NEXT:    if.end: %lv3 = load i16, ptr %c.sink, align 2
+; CHECK-NEXT:  LDist: Populated partitions:
+; CHECK-NEXT:  LDist: Partition 0: (cycle)
+; CHECK-NEXT:    for.body: %lv = load i16, ptr %A, align 1
+; CHECK-NEXT:    for.body: store i16 %lv, ptr %A, align 1
+; CHECK-NEXT:    if.then: %lv2 = load i16, ptr %A, align 1
+; CHECK-NEXT:    for.body: br i1 %c, label %if.then, label %if.end
+; CHECK-NEXT:    if.then: br label %if.end
+; CHECK-NEXT:    if.end: br i1 %tobool.not, label %for.end.loopexit, label %for.body
+; CHECK-NEXT:    if.end: %tobool.not = icmp eq i16 %iv.next, 1000
+; CHECK-NEXT:    if.end: %iv.next = add nuw nsw i16 %iv, 1
+; CHECK-NEXT:    for.body: %iv = phi i16 [ 0, %entry ], [ %iv.next, %if.end ]
+; CHECK-NEXT:  LDist: Partition 1:
+; CHECK-NEXT:    if.end: %lv3 = load i16, ptr %c.sink, align 2
+; CHECK-NEXT:    for.body: br i1 %c, label %if.then, label %if.end
+; CHECK-NEXT:    if.then: br label %if.end
+; CHECK-NEXT:    if.end: br i1 %tobool.not, label %for.end.loopexit, label %for.body
+; CHECK-NEXT:    if.end: %tobool.not = icmp eq i16 %iv.next, 1000
+; CHECK-NEXT:    if.end: %iv.next = add nuw nsw i16 %iv, 1
+; CHECK-NEXT:    for.body: %iv = phi i16 [ 0, %entry ], [ %iv.next, %if.end ]
+; CHECK-NEXT:    if.end: %c.sink = phi ptr [ %B, %if.then ], [ %C, %for.body ]
+; CHECK-NEXT:  LDist: Distributing loop: for.body
+; CHECK-NEXT:  LDist: Pointers:
+; CHECK-NEXT:  Check 0:
+; CHECK-NEXT:    Comparing group ([[GRP1:0x[0-9a-f]+]]):
+; CHECK-NEXT:    ptr %A
+; CHECK-NEXT:    ptr %A
+; CHECK-NEXT:    Against group ([[GRP2:0x[0-9a-f]+]]):
+; CHECK-NEXT:    ptr %C
+; CHECK-NEXT:  Check 1:
+; CHECK-NEXT:    Comparing group ([[GRP1]]):
+; CHECK-NEXT:    ptr %A
+; CHECK-NEXT:    ptr %A
+; CHECK-NEXT:    Against group ([[GRP3:0x[0-9a-f]+]]):
+; CHECK-NEXT:    ptr %B
+; CHECK-NEXT:  LDist: After removing unused Instrs:
+; CHECK-NEXT:  LDist: Partition 0:
+; CHECK-NEXT:  for.body.ldist1: ; preds = %if.end.ldist1, %for.body.ph.ldist1
+; CHECK-NEXT:    %iv.ldist1 = phi i16 [ 0, %for.body.ph.ldist1 ], [ %iv.next.ldist1, %if.end.ldist1 ]
+; CHECK-NEXT:    %lv.ldist1 = load i16, ptr %A, align 1, !alias.scope !0, !noalias !3
+; CHECK-NEXT:    store i16 %lv.ldist1, ptr %A, align 1, !alias.scope !0, !noalias !3
+; CHECK-NEXT:    br i1 %c, label %if.then.ldist1, label %if.end.ldist1
+; CHECK-EMPTY:
+; CHECK-NEXT:  if.then.ldist1: ; preds = %for.body.ldist1
+; CHECK-NEXT:    %lv2.ldist1 = load i16, ptr %A, align 1, !alias.scope !0, !noalias !3
+; CHECK-NEXT:    br label %if.end.ldist1
+; CHECK-EMPTY:
+; CHECK-NEXT:  if.end.ldist1: ; preds = %if.then.ldist1, %for.body.ldist1
+; CHECK-NEXT:    %iv.next.ldist1 = add nuw nsw i16 %iv.ldist1, 1
+; CHECK-NEXT:    %tobool.not.ldist1 = icmp eq i16 %iv.next.ldist1, 1000
+; CHECK-NEXT:    br i1 %tobool.not.ldist1, label %for.body.ph, label %for.body.ldist1
+; CHECK-NEXT:  LDist: Partition 1:
+; CHECK-NEXT:  for.body: ; preds = %if.end, %for.body.ph
+; CHECK-NEXT:    %iv = phi i16 [ 0, %for.body.ph ], [ %iv.next, %if.end ]
+; CHECK-NEXT:    br i1 %c, label %if.then, label %if.end
+; CHECK-EMPTY:
+; CHECK-NEXT:  if.then: ; preds = %for.body
+; CHECK-NEXT:    br label %if.end
+; CHECK-EMPTY:
+; CHECK-NEXT:  if.end: ; preds = %if.then, %for.body
+; CHECK-NEXT:    %c.sink = phi ptr [ %B, %if.then ], [ %C, %for.body ]
+; CHECK-NEXT:    %lv3 = load i16, ptr %c.sink, align 2
+; CHECK-NEXT:    %iv.next = add nuw nsw i16 %iv, 1
+; CHECK-NEXT:    %tobool.not = icmp eq i16 %iv.next, 1000
+; CHECK-NEXT:    br i1 %tobool.not, label %for.end.loopexit.loopexit6, label %for.body
+;
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %if.end, %entry
+  %iv = phi i16 [ 0, %entry ], [ %iv.next, %if.end ]
+  %lv = load i16, ptr %A, align 1
+  store i16 %lv, ptr %A, align 1
+  br i1 %c, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %lv2 = load i16, ptr %A, align 1
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  %c.sink = phi ptr [ %B, %if.then ], [ %C, %for.body ]
+  %lv3 = load i16, ptr %c.sink
+  %iv.next = add nuw nsw i16 %iv, 1
+  %tobool.not = icmp eq i16 %iv.next, 1000
+  br i1 %tobool.not, label %for.end.loopexit, label %for.body
+
+for.end.loopexit:                                 ; preds = %if.end
+  ret void
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_analyze_test_checks/loop-distribute.test b/llvm/test/tools/UpdateTestChecks/update_analyze_test_checks/loop-distribute.test
new file mode 100644
index 00000000000000..65a44fafc7d5a0
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_analyze_test_checks/loop-distribute.test
@@ -0,0 +1,6 @@
+## Basic test checking that update_analyze_test_checks.py works correctly
+# RUN: cp -f %S/Inputs/loop-distribute.ll %t.ll && %update_analyze_test_checks %t.ll
+# RUN: diff -u %t.ll %S/Inputs/loop-distribute.ll.expected
+## Check that running the script again does not change the result:
+# RUN: %update_analyze_test_checks %t.ll
+# RUN: diff -u %t.ll %S/Inputs/loop-distribute.ll.expected
diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py
index 85c129488d950e..eb212ed304e9db 100644
--- a/llvm/utils/UpdateTestChecks/common.py
+++ b/llvm/utils/UpdateTestChecks/common.py
@@ -569,7 +569,7 @@ def invoke_tool(exe, cmd_args, ir, preprocess_cmd=None, verbose=False):
     flags=(re.X | re.S),
 )
 
-LV_DEBUG_RE = re.compile(
+LOOP_PASS_DEBUG_RE = re.compile(
     r"^\s*\'(?P<func>[\w.$-]+?)\'[^\n]*" r"\s*\n(?P<body>.*)$", flags=(re.X | re.S)
 )
 
@@ -973,6 +973,7 @@ class NamelessValue:
     name (as in e.g. `@some_global` or `%x`) or just a number (as in e.g. `%12`
     or `!4`).
     """
+
     def __init__(
         self,
         check_prefix,
@@ -1635,8 +1636,9 @@ def generalize_check_lines(
         regexp = ginfo.get_regexp()
 
     multiple_braces_re = re.compile(r"({{+)|(}}+)")
+
     def escape_braces(match_obj):
-        return '{{' + re.escape(match_obj.group(0)) + '}}'
+        return "{{" + re.escape(match_obj.group(0)) + "}}"
 
     if ginfo.is_ir():
         for i, line in enumerate(lines):
diff --git a/llvm/utils/update_analyze_test_checks.py b/llvm/utils/update_analyze_test_checks.py
index 47506626a0a58b..d356ebead0d81a 100755
--- a/llvm/utils/update_analyze_test_checks.py
+++ b/llvm/utils/update_analyze_test_checks.py
@@ -134,13 +134,15 @@ def main():
                         raw_tool_output,
                         prefixes,
                     )
-            elif re.search(r"LV: Checking a loop in ", raw_tool_outputs) is not None:
-                # Split analysis outputs by "Printing analysis " declarations.
+            elif (
+                re.search(r"(LV|LDist): Checking a loop in ", raw_tool_outputs)
+                is not None
+            ):
                 for raw_tool_output in re.split(
-                    r"LV: Checking a loop in ", raw_tool_outputs
+                    r"(LV|LDist): Checking a loop in ", raw_tool_outputs
                 ):
                     builder.process_run_line(
-                        common.LV_DEBUG_RE,
+                        common.LOOP_PASS_DEBUG_RE,
                         common.scrub_body,
                         raw_tool_output,
                         prefixes,



More information about the llvm-commits mailing list