https://github.com/zahiraam created 
https://github.com/llvm/llvm-project/pull/208533

…ructs

>From 444217556666673b9efe64e2edb40ff08d777f16 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <[email protected]>
Date: Thu, 9 Jul 2026 11:10:26 -0700
Subject: [PATCH] [OpenMP] Restore loop variable values after
 loop-transformation constructs

---
 clang/lib/Sema/SemaOpenMP.cpp               |  44 ++++++-
 clang/test/OpenMP/loop_transform_final_iv.c | 129 ++++++++++++++++++++
 2 files changed, 172 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/OpenMP/loop_transform_final_iv.c

diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 0f45a21c5e461..b2605e41bb513 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -14960,6 +14960,31 @@ static Expr *makeFloorIVRef(Sema &SemaRef, 
ArrayRef<VarDecl *> FloorIndVars,
                           OrigCntVar->getExprLoc());
 }
 
+/// Add loop variable finalization statements to restore original loop variable
+/// values after a loop-transformation construct, as required by OpenMP 6.0 
spec
+/// (pg 371, lines 19-21).
+static Stmt *addLoopVarFinalization(
+    ASTContext &Context, Stmt *TransformedStmt,
+    ArrayRef<OMPLoopBasedDirective::HelperExprs> LoopHelpers) {
+  SmallVector<Stmt *, 8> FinalizationStmts;
+  FinalizationStmts.push_back(TransformedStmt);
+
+  for (const auto &LoopHelper : LoopHelpers) {
+    if (!LoopHelper.Finals.empty()) {
+      if (Expr *Final = LoopHelper.Finals[0]) {
+        FinalizationStmts.push_back(Final);
+      }
+    }
+  }
+
+  if (FinalizationStmts.size() > 1) {
+    return CompoundStmt::Create(Context, FinalizationStmts, 
FPOptionsOverride(),
+                                TransformedStmt->getBeginLoc(),
+                                TransformedStmt->getEndLoc());
+  }
+  return TransformedStmt;
+}
+
 StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
                                                 Stmt *AStmt,
                                                 SourceLocation StartLoc,
@@ -15230,6 +15255,8 @@ StmtResult 
SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
                 LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
   }
 
+  Inner = addLoopVarFinalization(Context, Inner, LoopHelpers);
+
   return OMPTileDirective::Create(Context, StartLoc, EndLoc, Clauses, NumLoops,
                                   AStmt, Inner,
                                   buildPreInits(Context, PreInits));
@@ -15489,6 +15516,8 @@ StmtResult 
SemaOpenMP::ActOnOpenMPStripeDirective(ArrayRef<OMPClause *> Clauses,
                 LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
   }
 
+  Inner = addLoopVarFinalization(Context, Inner, LoopHelpers);
+
   return OMPStripeDirective::Create(Context, StartLoc, EndLoc, Clauses,
                                     NumLoops, AStmt, Inner,
                                     buildPreInits(Context, PreInits));
@@ -15957,8 +15986,11 @@ StmtResult 
SemaOpenMP::ActOnOpenMPReverseDirective(Stmt *AStmt,
       ForStmt(Context, Init.get(), Cond.get(), nullptr, Incr.get(),
               ReversedBody, LoopHelper.Init->getBeginLoc(),
               LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
+
+  Stmt *Inner = addLoopVarFinalization(Context, ReversedFor, LoopHelpers);
+
   return OMPReverseDirective::Create(Context, StartLoc, EndLoc, AStmt, 
NumLoops,
-                                     ReversedFor,
+                                     Inner,
                                      buildPreInits(Context, PreInits));
 }
 
@@ -16381,6 +16413,8 @@ StmtResult SemaOpenMP::ActOnOpenMPInterchangeDirective(
         SourceHelper.Inc->getEndLoc());
   }
 
+  Inner = addLoopVarFinalization(Context, Inner, LoopHelpers);
+
   return OMPInterchangeDirective::Create(Context, StartLoc, EndLoc, Clauses,
                                          NumLoops, AStmt, Inner,
                                          buildPreInits(Context, PreInits));
@@ -16859,6 +16893,14 @@ StmtResult 
SemaOpenMP::ActOnOpenMPFuseDirective(ArrayRef<OMPClause *> Clauses,
     FusionStmt = CompoundStmt::Create(Context, FinalLoops, FPOptionsOverride(),
                                       SourceLocation(), SourceLocation());
   }
+
+  // Collect HelperExprs from all loops for finalization
+  SmallVector<OMPLoopBasedDirective::HelperExprs, 2> LoopHelpers;
+  for (const auto &Loop : SeqAnalysis.Loops) {
+    LoopHelpers.push_back(Loop.HelperExprs);
+  }
+  FusionStmt = addLoopVarFinalization(Context, FusionStmt, LoopHelpers);
+
   return OMPFuseDirective::Create(Context, StartLoc, EndLoc, Clauses,
                                   NumGeneratedTopLevelLoops, AStmt, FusionStmt,
                                   buildPreInits(Context, PreInits));
diff --git a/clang/test/OpenMP/loop_transform_final_iv.c 
b/clang/test/OpenMP/loop_transform_final_iv.c
new file mode 100644
index 0000000000000..969badbe9636b
--- /dev/null
+++ b/clang/test/OpenMP/loop_transform_final_iv.c
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=60 -emit-llvm %s -o - | 
FileCheck %s
+// expected-no-diagnostics
+
+// Test that loop variables are correctly finalized after loop-transformation
+// constructs as required by OpenMP 6.0 spec (pg 371, lines 19-21).
+
+void test_tile(void) {
+  // CHECK-LABEL: define {{.*}} @test_tile
+  int i;
+  #pragma omp tile sizes(2)
+  for (i = 1; i <= 10; i++) {
+  }
+  // CHECK: store i32 11, ptr %i
+  // After loop: i should be 11 (lb + tripcount * stride = 1 + 10 * 1)
+}
+
+void test_stripe(void) {
+  // CHECK-LABEL: define {{.*}} @test_stripe
+  int i;
+  #pragma omp stripe sizes(3)
+  for (i = 0; i < 10; i++) {
+  }
+  // CHECK: store i32 10, ptr %i
+  // After loop: i should be 10 (lb + tripcount * stride = 0 + 10 * 1)
+}
+
+void test_tile_nested(void) {
+  // CHECK-LABEL: define {{.*}} @test_tile_nested
+  int i, j;
+  #pragma omp tile sizes(2, 3)
+  for (i = 0; i < 10; i++)
+    for (j = 0; j < 5; j++) {
+    }
+  // CHECK: store i32 10, ptr %i
+  // CHECK: store i32 5, ptr %j
+  // After loop: i should be 10, j should be 5
+}
+
+void test_tile_stride(void) {
+  // CHECK-LABEL: define {{.*}} @test_tile_stride
+  int i;
+  #pragma omp tile sizes(4)
+  for (i = 5; i <= 15; i += 2) {
+  }
+  // CHECK: store i32 17, ptr %i
+  // After loop: i should be 17 (lb + tripcount * stride = 5 + 6 * 2)
+}
+
+void test_tile_variable_bound(int n) {
+  // CHECK-LABEL: define {{.*}} @test_tile_variable_bound
+  int i;
+  #pragma omp tile sizes(3)
+  for (i = 0; i < n; i++) {
+  }
+  // CHECK: for.end14:
+  // CHECK-NEXT: %{{.*}} = load i32, ptr %.capture_expr.
+  // CHECK-NEXT: %{{.*}} = sub nsw i32 %{{.*}}, 0
+  // CHECK-NEXT: %{{.*}} = sdiv i32 %{{.*}}, 1
+  // CHECK-NEXT: %{{.*}} = mul nsw i32 %{{.*}}, 1
+  // CHECK-NEXT: %{{.*}} = add nsw i32 0, %{{.*}}
+  // CHECK-NEXT: store i32 %{{.*}}, ptr %i
+  // After loop: i should equal n (the runtime upper bound)
+}
+
+void test_reverse(void) {
+  // CHECK-LABEL: define {{.*}} @test_reverse
+  int i;
+  #pragma omp reverse
+  for (i = 0; i < 10; i++) {
+  }
+  // CHECK: store i32 10, ptr %i
+  // After loop: i should be 10 (lb + tripcount * stride = 0 + 10 * 1)
+}
+
+void test_interchange(void) {
+  // CHECK-LABEL: define {{.*}} @test_interchange
+  int i, j;
+  #pragma omp interchange permutation(2, 1)
+  for (i = 0; i < 10; i++)
+    for (j = 0; j < 5; j++) {
+    }
+  // CHECK: store i32 10, ptr %i
+  // CHECK: store i32 5, ptr %j
+  // After loop: i should be 10, j should be 5
+}
+
+void test_fuse(void) {
+  // CHECK-LABEL: define {{.*}} @test_fuse
+  int i, j;
+  #pragma omp fuse
+  {
+  for (i = 0; i < 10; i++) {
+  }
+  for (j = 0; j < 5; j++) {
+  }
+  }
+  // CHECK: store i32 10, ptr %i
+  // CHECK: store i32 5, ptr %j
+  // After loop: i should be 10, j should be 5
+}
+
+void test_for_workshare(void) {
+  // CHECK-LABEL: define {{.*}} @test_for_workshare
+  int i;
+  #pragma omp for
+  for (i = 5; i <= 10; i += 2) {
+  }
+  // CHECK: omp.loop.exit:
+  // CHECK-NEXT: call void @__kmpc_for_static_fini
+  // CHECK-NEXT: call void @__kmpc_barrier
+  // CHECK-NEXT: ret void
+  // omp for worksharing doesn't finalize the loop variable after the loop
+}
+
+void test_for_lastprivate(void) {
+  // CHECK-LABEL: define {{.*}} @test_for_lastprivate
+  int i;
+  #pragma omp parallel
+  #pragma omp for lastprivate(i)
+  for (i = 5; i <= 10; i += 2) {
+  }
+  // CHECK: .omp.lastprivate.then:
+  // CHECK-NEXT: store i32 11, ptr %i{{.*}}, align 4
+  // CHECK-NEXT: %{{.*}} = load i32, ptr %i{{.*}}, align 4
+  // CHECK-NEXT: store i32 %{{.*}}, ptr %{{.*}}, align 4
+  // omp for with lastprivate DOES finalize the loop variable
+  // i = last_iteration_value + stride = 9 + 2 = 11
+}
+

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

Reply via email to