Author: Zahira Ammarguellat
Date: 2026-10-07T12:02:17Z
New Revision: 05559260278ec9d911ab9396f3258a313d229cbd

URL: 
https://github.com/llvm/llvm-project/commit/05559260278ec9d911ab9396f3258a313d229cbd
DIFF: 
https://github.com/llvm/llvm-project/commit/05559260278ec9d911ab9396f3258a313d229cbd.diff

LOG: [OpenMP] Tile/stripe followed by reverse (#222401)

`Clang` rejects `#pragma omp tile` or `#pragma omp stripe` immediately
followed by `#pragma omp reverse` on the same loop nest, emitting the
error:
`error: statement after '#pragma omp tile' must be a for loop`
See https://godbolt.org/z/d1fsfaMe9 

The correct behavior is to accept it. Bare`reverse`, bare
`tile`/`stripe`, and `tile` followed by `stripe` all work. Only
`tile`/`stripe` and `reverse` fails.
This PR fixes the issue.

Added: 
    clang/test/OpenMP/tile_stripe_reverse_ast_print.cpp
    openmp/runtime/test/transform/tile/tile-stripe-reverse.c

Modified: 
    clang/include/clang/AST/StmtOpenMP.h
    clang/lib/AST/StmtOpenMP.cpp
    clang/lib/Sema/SemaOpenMP.cpp
    clang/test/OpenMP/stripe_messages.cpp
    clang/test/OpenMP/tile_messages.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/StmtOpenMP.h 
b/clang/include/clang/AST/StmtOpenMP.h
index 773e1153ccdfc..a070d97a6db1f 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -905,6 +905,10 @@ class OMPLoopBasedDirective : public 
OMPExecutableDirective {
     return ignoreIntraTileHint(const_cast<Stmt *>(S));
   }
 
+  /// Returns the statements of \p Body that precede its last statement (the
+  /// nested loop), such as the user counter update `omp reverse` emits.
+  static ArrayRef<Stmt *> getStmtsBeforeNestedLoop(Stmt *Body);
+
   /// Calls the specified callback function for all the loops in \p CurStmt,
   /// from the outermost to the innermost.
   ///
@@ -913,6 +917,13 @@ class OMPLoopBasedDirective : public 
OMPExecutableDirective {
   /// nullptr if the loop has no such hint. Callers that need the hint (see
   /// checkOpenMPIterationSpace) can peel \p HintWrapper themselves; everyone
   /// else can ignore it.
+  ///
+  /// \p RelaxNestForPeeledTransformation allows a loop generated by a peeled
+  /// loop-transformation directive to hold statements before the next loop,
+  /// such as the user counter update `omp reverse` emits, so e.g. `omp tile`
+  /// accepts a nested `omp reverse` on a non-innermost loop. Only set it if 
the
+  /// caller re-emits those statements in the loops it generates; otherwise 
they
+  /// are dropped.
   static bool
   doForAllLoops(Stmt *CurStmt, bool TryImperfectlyNestedLoops,
                 unsigned NumLoops,
@@ -920,25 +931,29 @@ class OMPLoopBasedDirective : public 
OMPExecutableDirective {
                                         Stmt * /*HintWrapper*/)>
                     Callback,
                 llvm::function_ref<void(OMPLoopTransformationDirective *)>
-                    OnTransformationCallback);
+                    OnTransformationCallback,
+                bool RelaxNestForPeeledTransformation = false);
   static bool
   doForAllLoops(Stmt *CurStmt, bool TryImperfectlyNestedLoops,
                 unsigned NumLoops,
                 llvm::function_ref<bool(unsigned, Stmt *)> Callback,
                 llvm::function_ref<void(OMPLoopTransformationDirective *)>
-                    OnTransformationCallback) {
+                    OnTransformationCallback,
+                bool RelaxNestForPeeledTransformation = false) {
     auto &&NewCallback = [Callback](unsigned Cnt, Stmt *Loop, Stmt *) {
       return Callback(Cnt, Loop);
     };
     return doForAllLoops(CurStmt, TryImperfectlyNestedLoops, NumLoops,
-                         NewCallback, OnTransformationCallback);
+                         NewCallback, OnTransformationCallback,
+                         RelaxNestForPeeledTransformation);
   }
   static bool
   doForAllLoops(const Stmt *CurStmt, bool TryImperfectlyNestedLoops,
                 unsigned NumLoops,
                 llvm::function_ref<bool(unsigned, const Stmt *)> Callback,
                 llvm::function_ref<void(const OMPLoopTransformationDirective 
*)>
-                    OnTransformationCallback) {
+                    OnTransformationCallback,
+                bool RelaxNestForPeeledTransformation = false) {
     auto &&NewCallback = [Callback](unsigned Cnt, Stmt *CurStmt) {
       return Callback(Cnt, CurStmt);
     };
@@ -947,28 +962,31 @@ class OMPLoopBasedDirective : public 
OMPExecutableDirective {
           OnTransformationCallback(A);
         };
     return doForAllLoops(const_cast<Stmt *>(CurStmt), 
TryImperfectlyNestedLoops,
-                         NumLoops, NewCallback, NewTransformCb);
+                         NumLoops, NewCallback, NewTransformCb,
+                         RelaxNestForPeeledTransformation);
   }
 
   /// Calls the specified callback function for all the loops in \p CurStmt,
   /// from the outermost to the innermost.
-  static bool
-  doForAllLoops(Stmt *CurStmt, bool TryImperfectlyNestedLoops,
-                unsigned NumLoops,
-                llvm::function_ref<bool(unsigned, Stmt *)> Callback) {
+  static bool doForAllLoops(Stmt *CurStmt, bool TryImperfectlyNestedLoops,
+                            unsigned NumLoops,
+                            llvm::function_ref<bool(unsigned, Stmt *)> 
Callback,
+                            bool RelaxNestForPeeledTransformation = false) {
     auto &&TransformCb = [](OMPLoopTransformationDirective *) {};
     return doForAllLoops(CurStmt, TryImperfectlyNestedLoops, NumLoops, 
Callback,
-                         TransformCb);
+                         TransformCb, RelaxNestForPeeledTransformation);
   }
   static bool
   doForAllLoops(const Stmt *CurStmt, bool TryImperfectlyNestedLoops,
                 unsigned NumLoops,
-                llvm::function_ref<bool(unsigned, const Stmt *)> Callback) {
+                llvm::function_ref<bool(unsigned, const Stmt *)> Callback,
+                bool RelaxNestForPeeledTransformation = false) {
     auto &&NewCallback = [Callback](unsigned Cnt, const Stmt *CurStmt) {
       return Callback(Cnt, CurStmt);
     };
     return doForAllLoops(const_cast<Stmt *>(CurStmt), 
TryImperfectlyNestedLoops,
-                         NumLoops, NewCallback);
+                         NumLoops, NewCallback,
+                         RelaxNestForPeeledTransformation);
   }
 
   /// Calls the specified callback function for all the loop bodies in \p

diff  --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index 555e3454816ce..5ba11b2d8c42f 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -34,6 +34,13 @@ Stmt *OMPLoopBasedDirective::ignoreIntraTileHint(Stmt *S) {
   return S;
 }
 
+ArrayRef<Stmt *> OMPLoopBasedDirective::getStmtsBeforeNestedLoop(Stmt *Body) {
+  auto *CS = dyn_cast_or_null<CompoundStmt>(Body);
+  if (!CS || CS->size() < 2)
+    return {};
+  return ArrayRef(CS->body_begin(), CS->size() - 1);
+}
+
 /// Like `Stmt::IgnoreContainers`, but stops at (and preserves) an intra-tile
 /// hint wrapper so that the enclosing loop walker can deliver the hint to
 /// loop-associated analysis (e.g. `collapse`). Non-hint attributed statements
@@ -133,10 +140,12 @@ OMPLoopBasedDirective::tryToFindNextInnerLoop(Stmt 
*CurStmt,
         for (Stmt *S : CS->body()) {
           if (!S)
             continue;
-          // Peek past an OMPCanonicalLoop wrapper and/or an intra-tile hint to
-          // check whether this child is loop-like; keep the original (wrapped)
-          // node in CurStmt so the hint still reaches the loop-analysis
+          // Peek past a single-child container so a nested loop or
+          // loop-transformation directive (e.g. `#pragma omp reverse` inside
+          // the body of an outer loop) is recognized here. Preserve any
+          // intra-tile hint wrapper so it still reaches the loop-analysis
           // callback.
+          S = ignoreContainersKeepingIntraTileHint(S);
           Stmt *Inner = S;
           if (auto *CanonLoop = dyn_cast<OMPCanonicalLoop>(Inner))
             Inner = CanonLoop->getLoopStmt();
@@ -152,7 +161,7 @@ OMPLoopBasedDirective::tryToFindNextInnerLoop(Stmt *CurStmt,
             CurStmt = S;
             continue;
           }
-          S = S->IgnoreContainers();
+          S = OMPLoopBasedDirective::ignoreIntraTileHint(S);
           if (auto *InnerCS = dyn_cast_or_null<CompoundStmt>(S))
             NextStatements.push_back(InnerCS);
         }
@@ -174,9 +183,15 @@ bool OMPLoopBasedDirective::doForAllLoops(
     Stmt *CurStmt, bool TryImperfectlyNestedLoops, unsigned NumLoops,
     llvm::function_ref<bool(unsigned, Stmt *, Stmt *)> Callback,
     llvm::function_ref<void(OMPLoopTransformationDirective *)>
-        OnTransformationCallback) {
+        OnTransformationCallback,
+    bool RelaxNestForPeeledTransformation) {
   CurStmt = ignoreContainersKeepingIntraTileHint(CurStmt);
   for (unsigned Cnt = 0; Cnt < NumLoops; ++Cnt) {
+    // A loop generated by a peeled transformation may hold statements before
+    // the next loop (e.g. `reverse` recomputes the user counter there). They
+    // are not intervening user code, so callers that re-emit them may look
+    // through them; the rest of the nest is still checked as usual.
+    bool PeeledTransformation = false;
     while (true) {
       auto *Dir = dyn_cast<OMPLoopTransformationDirective>(CurStmt);
       if (!Dir)
@@ -202,6 +217,7 @@ bool OMPLoopBasedDirective::doForAllLoops(
       }
 
       CurStmt = TransformedStmt;
+      PeeledTransformation = true;
     }
     if (auto *CanonLoop = dyn_cast<OMPCanonicalLoop>(CurStmt))
       CurStmt = CanonLoop->getLoopStmt();
@@ -223,6 +239,9 @@ bool OMPLoopBasedDirective::doForAllLoops(
              "Expected canonical for or range-based for loops.");
       CurStmt = cast<CXXForRangeStmt>(LoopStmt)->getBody();
     }
+    if (RelaxNestForPeeledTransformation && PeeledTransformation &&
+        !getStmtsBeforeNestedLoop(CurStmt).empty())
+      CurStmt = cast<CompoundStmt>(CurStmt)->body_back();
     CurStmt = OMPLoopBasedDirective::tryToFindNextInnerLoop(
         CurStmt, TryImperfectlyNestedLoops);
   }

diff  --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index efc570a8933f1..d0cf844acf6db 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -15376,6 +15376,11 @@ bool SemaOpenMP::checkTransformableLoopNest(
     SmallVectorImpl<OMPLoopBasedDirective::HelperExprs> &LoopHelpers,
     Stmt *&Body, SmallVectorImpl<SmallVector<Stmt *>> &OriginalInits) {
   OriginalInits.emplace_back();
+  // Only tile and stripe re-emit the statements before the nested loop in a
+  // nested transformation's generated loop (see appendStmtsBeforeNestedLoop);
+  // other constructs would silently drop them.
+  bool RelaxNestForPeeledTransformation =
+      Kind == OMPD_tile || Kind == OMPD_stripe;
   bool Result = OMPLoopBasedDirective::doForAllLoops(
       AStmt->IgnoreContainers(), /*TryImperfectlyNestedLoops=*/false, NumLoops,
       [this, &LoopHelpers, &Body, &OriginalInits,
@@ -15411,7 +15416,8 @@ bool SemaOpenMP::checkTransformableLoopNest(
       },
       [&OriginalInits](OMPLoopTransformationDirective *Transform) {
         updatePreInits(Transform, OriginalInits.back());
-      });
+      },
+      RelaxNestForPeeledTransformation);
   assert(OriginalInits.back().empty() && "No preinit after innermost loop");
   OriginalInits.pop_back();
   return Result;
@@ -15713,7 +15719,8 @@ static void addLoopPreInits(ASTContext &Context,
 
 /// Collect the loop statements (ForStmt or CXXRangeForStmt) of the affected
 /// loop of a construct.
-static void collectLoopStmts(Stmt *AStmt, MutableArrayRef<Stmt *> LoopStmts) {
+static void collectLoopStmts(Stmt *AStmt, MutableArrayRef<Stmt *> LoopStmts,
+                             bool RelaxNestForPeeledTransformation = false) {
   size_t NumLoops = LoopStmts.size();
   OMPLoopBasedDirective::doForAllLoops(
       AStmt, /*TryImperfectlyNestedLoops=*/false, NumLoops,
@@ -15721,11 +15728,25 @@ static void collectLoopStmts(Stmt *AStmt, 
MutableArrayRef<Stmt *> LoopStmts) {
         assert(!LoopStmts[Cnt] && "Loop statement must not yet be assigned");
         LoopStmts[Cnt] = CurStmt;
         return false;
-      });
+      },
+      RelaxNestForPeeledTransformation);
   assert(!is_contained(LoopStmts, nullptr) &&
          "Expecting a loop statement for each affected loop");
 }
 
+/// A non-innermost affected loop generated by a nested loop transformation
+/// (e.g. `omp reverse`) computes the user counter in statements ahead of the
+/// next loop. A construct that rebuilds the nest only keeps the innermost
+/// body, so it must re-emit these statements in the matching loop.
+static void appendStmtsBeforeNestedLoop(Stmt *LoopStmt,
+                                        SmallVectorImpl<Stmt *> &BodyParts) {
+  Stmt *Body = isa<ForStmt>(LoopStmt)
+                   ? cast<ForStmt>(LoopStmt)->getBody()
+                   : cast<CXXForRangeStmt>(LoopStmt)->getBody();
+  llvm::append_range(BodyParts,
+                     OMPLoopBasedDirective::getStmtsBeforeNestedLoop(Body));
+}
+
 /// Build and return a DeclRefExpr for the floor induction variable using the
 /// SemaRef and the provided parameters.
 static Expr *makeFloorIVRef(Sema &SemaRef, ArrayRef<VarDecl *> FloorIndVars,
@@ -15774,7 +15795,7 @@ StmtResult 
SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
 
   // Collect all affected loop statements.
   SmallVector<Stmt *> LoopStmts(NumLoops, nullptr);
-  collectLoopStmts(AStmt, LoopStmts);
+  collectLoopStmts(AStmt, LoopStmts, 
/*RelaxNestForPeeledTransformation=*/true);
 
   SmallVector<Stmt *, 4> PreInits;
   CaptureVars CopyTransformer(SemaRef);
@@ -16023,6 +16044,8 @@ StmtResult 
SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
     BodyParts.append(LoopHelper.Updates.begin(), LoopHelper.Updates.end());
     if (auto *SourceCXXFor = dyn_cast<CXXForRangeStmt>(LoopStmt))
       BodyParts.push_back(SourceCXXFor->getLoopVarStmt());
+    if (static_cast<unsigned>(I) + 1 < NumLoops)
+      appendStmtsBeforeNestedLoop(LoopStmt, BodyParts);
     BodyParts.push_back(Inner);
     Inner = CompoundStmt::Create(Context, BodyParts, FPOptionsOverride(),
                                  Inner->getBeginLoc(), Inner->getEndLoc());
@@ -16131,7 +16154,7 @@ StmtResult 
SemaOpenMP::ActOnOpenMPStripeDirective(ArrayRef<OMPClause *> Clauses,
 
   // Collect all affected loop statements.
   SmallVector<Stmt *> LoopStmts(NumLoops, nullptr);
-  collectLoopStmts(AStmt, LoopStmts);
+  collectLoopStmts(AStmt, LoopStmts, 
/*RelaxNestForPeeledTransformation=*/true);
 
   SmallVector<Stmt *, 4> PreInits;
   CaptureVars CopyTransformer(SemaRef);
@@ -16293,6 +16316,8 @@ StmtResult 
SemaOpenMP::ActOnOpenMPStripeDirective(ArrayRef<OMPClause *> Clauses,
     BodyParts.append(LoopHelper.Updates.begin(), LoopHelper.Updates.end());
     if (auto *SourceCXXFor = dyn_cast<CXXForRangeStmt>(LoopStmt))
       BodyParts.push_back(SourceCXXFor->getLoopVarStmt());
+    if (static_cast<unsigned>(I) + 1 < NumLoops)
+      appendStmtsBeforeNestedLoop(LoopStmt, BodyParts);
     BodyParts.push_back(Inner);
     Inner = CompoundStmt::Create(Context, BodyParts, FPOptionsOverride(),
                                  Inner->getBeginLoc(), Inner->getEndLoc());

diff  --git a/clang/test/OpenMP/stripe_messages.cpp 
b/clang/test/OpenMP/stripe_messages.cpp
index 3f171f40d71d9..2e4675c35cc6c 100644
--- a/clang/test/OpenMP/stripe_messages.cpp
+++ b/clang/test/OpenMP/stripe_messages.cpp
@@ -169,3 +169,16 @@ void f() {
     ;
 }
 } // namespace GH139433
+
+// The loop generated by 'reverse' may be a non-innermost affected loop, but
+// user code between it and the next affected loop is still intervening code.
+void stripe_of_reverse_intervening() {
+  // expected-error@+3 {{statement after '#pragma omp stripe' must be a for 
loop}}
+#pragma omp stripe sizes(2, 2)
+#pragma omp reverse
+  for (int i = 0; i < 7; ++i) {
+    int k = 3;
+    for (int j = 0; j < 7; ++j)
+      ;
+  }
+}

diff  --git a/clang/test/OpenMP/tile_messages.cpp 
b/clang/test/OpenMP/tile_messages.cpp
index 021262ac9a54a..72ceef71566d6 100644
--- a/clang/test/OpenMP/tile_messages.cpp
+++ b/clang/test/OpenMP/tile_messages.cpp
@@ -210,3 +210,16 @@ void unroll_of_tile() {
     ;
 }
 } // namespace consumed_by_transformation
+
+// The loop generated by 'reverse' may be a non-innermost affected loop, but
+// user code between it and the next affected loop is still intervening code.
+void tile_of_reverse_intervening() {
+  // expected-error@+3 {{statement after '#pragma omp tile' must be a for 
loop}}
+#pragma omp tile sizes(2, 2)
+#pragma omp reverse
+  for (int i = 0; i < 7; ++i) {
+    int k = 3;
+    for (int j = 0; j < 7; ++j)
+      ;
+  }
+}

diff  --git a/clang/test/OpenMP/tile_stripe_reverse_ast_print.cpp 
b/clang/test/OpenMP/tile_stripe_reverse_ast_print.cpp
new file mode 100644
index 0000000000000..5eee992f50483
--- /dev/null
+++ b/clang/test/OpenMP/tile_stripe_reverse_ast_print.cpp
@@ -0,0 +1,79 @@
+// Check no warnings/errors
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 \
+// RUN: -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// Check AST and unparsing
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 \
+// RUN: -ast-print %s | FileCheck %s --check-prefix=PRINT
+
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 \
+// RUN: -emit-pch -o %t %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 \
+// RUN: -include-pch %t -ast-print %s | FileCheck %s --check-prefix=PRINT
+
+#ifndef HEADER
+#define HEADER
+
+extern "C" void body(...);
+
+// PRINT-LABEL: void tile_then_reverse(
+void tile_then_reverse() {
+  // PRINT: #pragma omp tile sizes(2, 2)
+  // PRINT: #pragma omp reverse
+#pragma omp tile sizes(2, 2)
+#pragma omp reverse
+  for (int i = 0; i < 20; ++i)
+    for (int j = 0; j < 20; ++j)
+      body(i, j);
+}
+
+// PRINT-LABEL: void stripe_then_reverse(
+void stripe_then_reverse() {
+  // PRINT: #pragma omp stripe sizes(2, 2)
+  // PRINT: #pragma omp reverse
+#pragma omp stripe sizes(2, 2)
+#pragma omp reverse
+  for (int i = 0; i < 20; ++i)
+    for (int j = 0; j < 20; ++j)
+      body(i, j);
+}
+
+// PRINT-LABEL: void tile_over_inner_reverse(
+void tile_over_inner_reverse() {
+  // PRINT: #pragma omp tile sizes(2, 2)
+#pragma omp tile sizes(2, 2)
+#pragma omp reverse
+  for (int j = 0; j < 20; ++j) {
+    // PRINT: #pragma omp reverse
+#pragma omp reverse
+    for (int i = 0; i < 20; ++i)
+      body(j, i);
+  }
+}
+
+// PRINT-LABEL: void stripe_over_inner_reverse(
+void stripe_over_inner_reverse() {
+  // PRINT: #pragma omp stripe sizes(2, 2)
+#pragma omp stripe sizes(2, 2)
+#pragma omp reverse
+  for (int j = 0; j < 20; ++j) {
+    // PRINT: #pragma omp reverse
+#pragma omp reverse
+    for (int i = 0; i < 20; ++i)
+      body(j, i);
+  }
+}
+
+// PRINT-LABEL: void for_collapse_then_reverse(
+void for_collapse_then_reverse() {
+  // PRINT: #pragma omp for collapse(2)
+  // PRINT: #pragma omp reverse
+#pragma omp for collapse(2)
+#pragma omp reverse
+  for (int j = 0; j < 20; j += 2)
+    for (int i = 0; i < 20; i += 3)
+      body(j, i);
+}
+
+#endif

diff  --git a/openmp/runtime/test/transform/tile/tile-stripe-reverse.c 
b/openmp/runtime/test/transform/tile/tile-stripe-reverse.c
new file mode 100644
index 0000000000000..7f599737b1e8a
--- /dev/null
+++ b/openmp/runtime/test/transform/tile/tile-stripe-reverse.c
@@ -0,0 +1,94 @@
+// RUN: %libomp-compile -fopenmp-version=60 && %libomp-run \
+// RUN:   | FileCheck %s --match-full-lines
+
+// tile/stripe over a reverse that is not the innermost affected loop must
+// keep the reversal (regression test for #222401).
+
+#ifndef HEADER
+#define HEADER
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+  printf("tile\n");
+#pragma omp tile sizes(2, 2)
+#pragma omp reverse
+  for (int i = 0; i < 4; ++i)
+    for (int j = 0; j < 4; ++j)
+      printf("i=%d j=%d\n", i, j);
+
+  printf("stripe\n");
+#pragma omp stripe sizes(2, 2)
+#pragma omp reverse
+  for (int i = 0; i < 4; ++i)
+    for (int j = 0; j < 4; ++j)
+      printf("i=%d j=%d\n", i, j);
+
+  printf("nested\n");
+#pragma omp tile sizes(2, 2)
+#pragma omp reverse
+  for (int j = 0; j < 4; ++j) {
+#pragma omp reverse
+    for (int i = 0; i < 4; ++i)
+      printf("j=%d i=%d\n", j, i);
+  }
+
+  printf("done\n");
+  return EXIT_SUCCESS;
+}
+
+#endif /* HEADER */
+
+// CHECK:      tile
+// CHECK-NEXT: i=3 j=0
+// CHECK-NEXT: i=3 j=1
+// CHECK-NEXT: i=2 j=0
+// CHECK-NEXT: i=2 j=1
+// CHECK-NEXT: i=3 j=2
+// CHECK-NEXT: i=3 j=3
+// CHECK-NEXT: i=2 j=2
+// CHECK-NEXT: i=2 j=3
+// CHECK-NEXT: i=1 j=0
+// CHECK-NEXT: i=1 j=1
+// CHECK-NEXT: i=0 j=0
+// CHECK-NEXT: i=0 j=1
+// CHECK-NEXT: i=1 j=2
+// CHECK-NEXT: i=1 j=3
+// CHECK-NEXT: i=0 j=2
+// CHECK-NEXT: i=0 j=3
+// CHECK-NEXT: stripe
+// CHECK-NEXT: i=3 j=0
+// CHECK-NEXT: i=3 j=1
+// CHECK-NEXT: i=2 j=0
+// CHECK-NEXT: i=2 j=1
+// CHECK-NEXT: i=3 j=2
+// CHECK-NEXT: i=3 j=3
+// CHECK-NEXT: i=2 j=2
+// CHECK-NEXT: i=2 j=3
+// CHECK-NEXT: i=1 j=0
+// CHECK-NEXT: i=1 j=1
+// CHECK-NEXT: i=0 j=0
+// CHECK-NEXT: i=0 j=1
+// CHECK-NEXT: i=1 j=2
+// CHECK-NEXT: i=1 j=3
+// CHECK-NEXT: i=0 j=2
+// CHECK-NEXT: i=0 j=3
+// CHECK-NEXT: nested
+// CHECK-NEXT: j=3 i=3
+// CHECK-NEXT: j=3 i=2
+// CHECK-NEXT: j=2 i=3
+// CHECK-NEXT: j=2 i=2
+// CHECK-NEXT: j=3 i=1
+// CHECK-NEXT: j=3 i=0
+// CHECK-NEXT: j=2 i=1
+// CHECK-NEXT: j=2 i=0
+// CHECK-NEXT: j=1 i=3
+// CHECK-NEXT: j=1 i=2
+// CHECK-NEXT: j=0 i=3
+// CHECK-NEXT: j=0 i=2
+// CHECK-NEXT: j=1 i=1
+// CHECK-NEXT: j=1 i=0
+// CHECK-NEXT: j=0 i=1
+// CHECK-NEXT: j=0 i=0
+// CHECK-NEXT: done


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to