[Openmp-commits] [openmp] 5db657b - [Clang][OpenMP] Convert `flatten` floating-point trip-count to integers (#229458)

via Openmp-commits openmp-commits at lists.llvm.org
Mon Oct 19 09:54:21 PDT 2026


Author: Amit Tiwari
Date: 2026-10-19T22:24:15+05:30
New Revision: 5db657b9d7afdf469398f562288aba6aa2fb68e4

URL: https://github.com/llvm/llvm-project/commit/5db657b9d7afdf469398f562288aba6aa2fb68e4
DIFF: https://github.com/llvm/llvm-project/commit/5db657b9d7afdf469398f562288aba6aa2fb68e4.diff

LOG: [Clang][OpenMP] Convert `flatten` floating-point trip-count to integers  (#229458)

Fixes #225753

Solution: The compiler now turns that trip count into an integer before
it builds the flattened loop. The width follows the existing rule. If
the loop variable is an integer, the new count keeps that variable's
signedness, so a `long` loop with a `double` count stays signed.

If the conversion fails, `flatten` returns an error instead of aborting.

Added: 
    openmp/runtime/test/transform/flatten/floating-bounds.c

Modified: 
    clang/lib/Sema/SemaOpenMP.cpp
    clang/test/OpenMP/flatten_codegen.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index efe8c9338b5a9..6a77044ed4988 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -17368,10 +17368,32 @@ SemaOpenMP::ActOnOpenMPFlattenDirective(ArrayRef<OMPClause *> Clauses,
   }
 
   CaptureVars CopyTransformer(SemaRef);
-  auto MakeNumIterations = [&CopyTransformer,
-                            &LoopHelpers](unsigned I) -> Expr * {
-    return AssertSuccess(
-        CopyTransformer.TransformExpr(LoopHelpers[I].NumIterations));
+  // Convert a non-integer trip count. Width matches buildNumIterations.
+  // Signedness follows an integer loop variable so a float count stays signed.
+  auto MakeNumIterations = [&CopyTransformer, &LoopHelpers, &Context,
+                            &SemaRef =
+                                this->SemaRef](unsigned I) -> ExprResult {
+    ExprResult N = CopyTransformer.TransformExpr(LoopHelpers[I].NumIterations);
+    if (!N.isUsable())
+      return ExprError();
+    QualType Type = N.get()->getType();
+    if (Type->isIntegerType())
+      return N;
+    const auto *Counter = cast<DeclRefExpr>(LoopHelpers[I].Counters.front());
+    QualType VarType = Counter->getType().getNonReferenceType();
+    bool VarIsInt = VarType->hasIntegerRepresentation();
+    bool UseVarWidth =
+        VarIsInt && Context.getTypeSize(Type) > Context.getTypeSize(VarType);
+    unsigned NewSize =
+        UseVarWidth ? Context.getTypeSize(VarType) : Context.getTypeSize(Type);
+    bool IsSigned = VarIsInt ? VarType->hasSignedIntegerRepresentation()
+                             : Type->hasFloatingRepresentation();
+    QualType IntTy = getIntTypeForBitwidthOrBitInt(Context, NewSize, IsSigned);
+    N = SemaRef.PerformImplicitConversion(
+        N.get(), IntTy, AssignmentAction::Converting, /*AllowExplicit=*/true);
+    if (!N.isUsable())
+      return ExprError();
+    return N;
   };
 
   OMPLoopBasedDirective::HelperExprs &OutermostHelper = LoopHelpers[0];
@@ -17386,7 +17408,10 @@ SemaOpenMP::ActOnOpenMPFlattenDirective(ArrayRef<OMPClause *> Clauses,
   auto BuildTripCount = [&](unsigned Bits) -> ExprResult {
     ExprResult Product;
     for (unsigned I = 0; I < NumLoops; ++I) {
-      ExprResult N = widenIterationCount(Bits, MakeNumIterations(I), SemaRef);
+      ExprResult N = MakeNumIterations(I);
+      if (!N.isUsable())
+        return ExprError();
+      N = widenIterationCount(Bits, N.get(), SemaRef);
       if (!N.isUsable())
         return ExprError();
       if (I == 0)
@@ -17464,27 +17489,31 @@ SemaOpenMP::ActOnOpenMPFlattenDirective(ArrayRef<OMPClause *> Clauses,
   if (!TripCount.isUsable())
     return StmtError();
 
-  auto MakeNumIterationsInIVTy = [&](unsigned I) -> Expr * {
-    return AssertSuccess(SemaRef.PerformImplicitConversion(
-        MakeNumIterations(I), IVTy, AssignmentAction::Converting,
-        /*AllowExplicit=*/true));
+  auto MakeNumIterationsInIVTy = [&](unsigned I) -> ExprResult {
+    ExprResult N = MakeNumIterations(I);
+    if (!N.isUsable())
+      return ExprError();
+    return SemaRef.PerformImplicitConversion(
+        N.get(), IVTy, AssignmentAction::Converting, /*AllowExplicit=*/true);
   };
 
   // Divisors in index recovery use (N == 0 ? 1 : N) so a zero trip count does
   // not warn.
-  auto MakeDivisorInIVTy = [&](unsigned I) -> Expr * {
-    Expr *N = MakeNumIterationsInIVTy(I);
-    Expr *NCmp = MakeNumIterationsInIVTy(I);
+  auto MakeDivisorInIVTy = [&](unsigned I) -> ExprResult {
+    ExprResult N = MakeNumIterationsInIVTy(I);
+    ExprResult NCmp = MakeNumIterationsInIVTy(I);
+    if (!N.isUsable() || !NCmp.isUsable())
+      return ExprError();
     auto MakeCst = [&](uint64_t V) -> Expr * {
       return IntegerLiteral::Create(Context, llvm::APInt(IVWidth, V), IVTy,
                                     CondLoc);
     };
     ExprResult IsZero =
-        SemaRef.BuildBinOp(CurScope, CondLoc, BO_EQ, NCmp, MakeCst(0));
+        SemaRef.BuildBinOp(CurScope, CondLoc, BO_EQ, NCmp.get(), MakeCst(0));
     if (!IsZero.isUsable())
       return N;
-    return AssertSuccess(SemaRef.ActOnConditionalOp(
-        CondLoc, CondLoc, IsZero.get(), MakeCst(1), N));
+    return SemaRef.ActOnConditionalOp(CondLoc, CondLoc, IsZero.get(),
+                                      MakeCst(1), N.get());
   };
 
   // \code{.cpp}
@@ -17549,9 +17578,14 @@ SemaOpenMP::ActOnOpenMPFlattenDirective(ArrayRef<OMPClause *> Clauses,
     ExprResult Value = MakeFlattenedRef();
     if (I + 1 < NumLoops) {
       ExprResult Divisor = MakeDivisorInIVTy(I + 1);
+      if (!Divisor.isUsable())
+        return StmtError();
       for (unsigned J = I + 2; J < NumLoops; ++J) {
+        ExprResult Next = MakeDivisorInIVTy(J);
+        if (!Next.isUsable())
+          return StmtError();
         Divisor = SemaRef.BuildBinOp(CurScope, OrigVarLoc, BO_Mul,
-                                     Divisor.get(), MakeDivisorInIVTy(J));
+                                     Divisor.get(), Next.get());
         if (!Divisor.isUsable())
           return StmtError();
       }
@@ -17561,8 +17595,11 @@ SemaOpenMP::ActOnOpenMPFlattenDirective(ArrayRef<OMPClause *> Clauses,
         return StmtError();
     }
     if (I > 0) {
+      ExprResult RemDivisor = MakeDivisorInIVTy(I);
+      if (!RemDivisor.isUsable())
+        return StmtError();
       Value = SemaRef.BuildBinOp(CurScope, OrigVarLoc, BO_Rem, Value.get(),
-                                 MakeDivisorInIVTy(I));
+                                 RemDivisor.get());
       if (!Value.isUsable())
         return StmtError();
     }

diff  --git a/clang/test/OpenMP/flatten_codegen.cpp b/clang/test/OpenMP/flatten_codegen.cpp
index 109aa16e3e079..f9bc03c55ed2c 100644
--- a/clang/test/OpenMP/flatten_codegen.cpp
+++ b/clang/test/OpenMP/flatten_codegen.cpp
@@ -102,6 +102,34 @@ extern "C" void both_neg() {
       body(i, j);
 }
 
+// A floating-point expression that initializes an integer loop counter can
+// make the calculated trip count floating-point. Flatten converts such counts
+// to an integer type before building its flattened induction variable.
+// CHECK-LABEL: define {{.*}}void @floating_init(
+// CHECK:   %.flatten.iv = alloca i32
+// CHECK:   icmp slt i32
+// CHECK:   sdiv i32
+// CHECK:   srem i32
+extern "C" void floating_init() {
+#pragma omp flatten
+  for (int i = 0; i < 2; ++i)
+    for (int j = 0.; j < 2; ++j)
+      body(i, j);
+}
+
+// long and double are the same width, so the count is not narrowed to the
+// variable. Signedness still follows the signed loop variable (i64, not u64).
+// CHECK-LABEL: define {{.*}}void @floating_long(
+// CHECK:   %.flatten.iv = alloca i64
+// CHECK:   icmp slt i64
+// CHECK:   sdiv i64
+extern "C" void floating_long() {
+#pragma omp flatten
+  for (long i = 0.; i < 2; ++i)
+    for (int j = 0; j < 2; ++j)
+      body(0, 0);
+}
+
 // Mixed signed/unsigned trip counts: the flattened IV is unsigned, and the
 // signed inner count is converted into that type for (N == 0 ? 1 : N).
 // CHECK-LABEL: define {{.*}}void @mixed_sign(

diff  --git a/openmp/runtime/test/transform/flatten/floating-bounds.c b/openmp/runtime/test/transform/flatten/floating-bounds.c
new file mode 100644
index 0000000000000..1c45b5febbecf
--- /dev/null
+++ b/openmp/runtime/test/transform/flatten/floating-bounds.c
@@ -0,0 +1,32 @@
+// RUN: %libomp-compile -fopenmp-version=61 && %libomp-run \
+// RUN:   | FileCheck %s --match-full-lines
+
+#ifndef HEADER
+#define HEADER
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(void) {
+  int count = 0;
+
+#pragma omp flatten
+  for (int i = 0; i < 2; ++i)
+    for (int j = 0.; j < 2; ++j)
+      ++count;
+  printf("floating-init=%d\n", count);
+
+  count = 0;
+#pragma omp flatten
+  for (int i = 0; i < 2; ++i)
+    for (int j = 0; j < 2.; ++j)
+      ++count;
+  printf("floating-bound=%d\n", count);
+
+  return EXIT_SUCCESS;
+}
+
+#endif /* HEADER */
+
+// CHECK:      floating-init=4
+// CHECK-NEXT: floating-bound=4


        


More information about the Openmp-commits mailing list