[clang] [Clang][OpenMP] Optimize `collapse` IV bit-width precision expression (PR #225612)
Amit Tiwari via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 25 02:16:38 PDT 2026
https://github.com/loopacino updated https://github.com/llvm/llvm-project/pull/225612
>From 7bd7db9dc6f3902fdc68ebc631efda01f66f679d Mon Sep 17 00:00:00 2001
From: amtiwari <amtiwari at amd.com>
Date: Wed, 23 Sep 2026 02:55:31 -0400
Subject: [PATCH 1/3] optimize bit-width
---
clang/lib/Sema/SemaOpenMP.cpp | 102 +++++++++---------
.../test/OpenMP/collapse_iv_width_codegen.cpp | 52 +++++++++
2 files changed, 105 insertions(+), 49 deletions(-)
create mode 100644 clang/test/OpenMP/collapse_iv_width_codegen.cpp
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 88b642b73895f9..865da6f5aa0fde 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -10363,29 +10363,10 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// Precondition tests if there is at least one iteration (all conditions are
// true).
auto PreCond = ExprResult(IterSpaces[0].PreCond);
- Expr *N0 = IterSpaces[0].NumIterations;
- ExprResult LastIteration32 = widenIterationCount(
- /*Bits=*/32,
- SemaRef
- .PerformImplicitConversion(N0->IgnoreImpCasts(), N0->getType(),
- AssignmentAction::Converting,
- /*AllowExplicit=*/true)
- .get(),
- SemaRef);
- ExprResult LastIteration64 = widenIterationCount(
- /*Bits=*/64,
- SemaRef
- .PerformImplicitConversion(N0->IgnoreImpCasts(), N0->getType(),
- AssignmentAction::Converting,
- /*AllowExplicit=*/true)
- .get(),
- SemaRef);
-
- if (!LastIteration32.isUsable() || !LastIteration64.isUsable())
- return NestedLoopCount;
-
ASTContext &C = SemaRef.Context;
- bool AllCountsNeedLessThan32Bits = C.getTypeSize(N0->getType()) < 32;
+ unsigned FirstCountBits =
+ C.getTypeSize(IterSpaces[0].NumIterations->getType());
+ bool AllCountsNeedLessThan32Bits = FirstCountBits < 32;
Scope *CurScope = DSA.getCurScope();
for (unsigned Cnt = 1; Cnt < NestedLoopCount; ++Cnt) {
@@ -10395,37 +10376,63 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
PreCond.get(), IterSpaces[Cnt].PreCond);
}
Expr *N = IterSpaces[Cnt].NumIterations;
- SourceLocation Loc = N->getExprLoc();
AllCountsNeedLessThan32Bits &= C.getTypeSize(N->getType()) < 32;
- if (LastIteration32.isUsable())
- LastIteration32 = SemaRef.BuildBinOp(
- CurScope, Loc, BO_Mul, LastIteration32.get(),
- SemaRef
- .PerformImplicitConversion(N->IgnoreImpCasts(), N->getType(),
- AssignmentAction::Converting,
- /*AllowExplicit=*/true)
- .get());
- if (LastIteration64.isUsable())
- LastIteration64 = SemaRef.BuildBinOp(
- CurScope, Loc, BO_Mul, LastIteration64.get(),
+ }
+
+ auto BuildLastIteration = [&](unsigned Bits) -> ExprResult {
+ ExprResult Result;
+ for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
+ Expr *N = IterSpaces[Cnt].NumIterations;
+ ExprResult Count = widenIterationCount(
+ Bits,
SemaRef
.PerformImplicitConversion(N->IgnoreImpCasts(), N->getType(),
AssignmentAction::Converting,
/*AllowExplicit=*/true)
- .get());
- }
+ .get(),
+ SemaRef);
+ if (!Count.isUsable())
+ return ExprError();
+ if (Cnt == 0)
+ Result = Count;
+ else
+ Result = SemaRef.BuildBinOp(CurScope, N->getExprLoc(), BO_Mul,
+ Result.get(), Count.get());
+ if (!Result.isUsable())
+ return ExprError();
+ }
+ return Result;
+ };
- // Choose either the 32-bit or 64-bit version.
- ExprResult LastIteration = LastIteration64;
+ // Build the 32-bit tree immediately only when it is always selected.
+ // Otherwise, build the 64-bit tree first and build the 32-bit tree only when
+ // the constant product may fit.
+ ExprResult LastIteration;
if (SemaRef.getLangOpts().OpenMPOptimisticCollapse ||
- (LastIteration32.isUsable() &&
- C.getTypeSize(LastIteration32.get()->getType()) == 32 &&
- (AllCountsNeedLessThan32Bits || NestedLoopCount == 1 ||
- fitsInto(
- /*Bits=*/32,
- LastIteration32.get()->getType()->hasSignedIntegerRepresentation(),
- LastIteration64.get(), SemaRef))))
- LastIteration = LastIteration32;
+ AllCountsNeedLessThan32Bits ||
+ (NestedLoopCount == 1 && FirstCountBits == 32)) {
+ LastIteration = BuildLastIteration(/*Bits=*/32);
+ } else {
+ ExprResult LastIteration64 = BuildLastIteration(/*Bits=*/64);
+ if (!LastIteration64.isUsable())
+ return NestedLoopCount;
+ LastIteration = LastIteration64;
+ if (LastIteration64.get()->isIntegerConstantExpr(C)) {
+ ExprResult LastIteration32 = BuildLastIteration(/*Bits=*/32);
+ if (LastIteration32.isUsable() &&
+ C.getTypeSize(LastIteration32.get()->getType()) == 32 &&
+ fitsInto(
+ /*Bits=*/32,
+ LastIteration32.get()
+ ->getType()
+ ->hasSignedIntegerRepresentation(),
+ LastIteration64.get(), SemaRef))
+ LastIteration = LastIteration32;
+ }
+ }
+ if (!LastIteration.isUsable())
+ return NestedLoopCount;
+
QualType VType = LastIteration.get()->getType();
QualType RealVType = VType;
QualType StrideVType = VType;
@@ -10436,9 +10443,6 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
SemaRef.Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
}
- if (!LastIteration.isUsable())
- return 0;
-
// Save the number of iterations.
ExprResult NumIterations = LastIteration;
{
diff --git a/clang/test/OpenMP/collapse_iv_width_codegen.cpp b/clang/test/OpenMP/collapse_iv_width_codegen.cpp
new file mode 100644
index 00000000000000..2a1d0dcc9f19a5
--- /dev/null
+++ b/clang/test/OpenMP/collapse_iv_width_codegen.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -verify -fopenmp -std=c++20 -x c++ -triple x86_64-unknown-unknown \
+// RUN: -Wno-bit-int-extension -emit-llvm %s -o - | FileCheck %s
+
+// expected-no-diagnostics
+
+void one_i32(unsigned n) {
+#pragma omp parallel for collapse(1)
+ for (unsigned i = 0; i < n; ++i)
+ ;
+}
+
+// CHECK-LABEL: define internal void @_Z7one_i32j.omp_outlined(
+// CHECK: call void @__kmpc_for_static_init_4u(
+
+void one_i40(_BitInt(40) n) {
+#pragma omp parallel for collapse(1)
+ for (_BitInt(40) i = 0; i < n; ++i)
+ ;
+}
+
+// CHECK-LABEL: define internal void @_Z7one_i40DB40_.omp_outlined(
+// CHECK: call void @__kmpc_for_static_init_8(
+
+void dynamic_two(unsigned n, unsigned m) {
+#pragma omp parallel for collapse(2)
+ for (unsigned i = 0; i < n; ++i)
+ for (unsigned j = 0; j < m; ++j)
+ ;
+}
+
+// CHECK-LABEL: define internal void @_Z11dynamic_twojj.omp_outlined(
+// CHECK: call void @__kmpc_for_static_init_8(
+
+void fit_constant() {
+#pragma omp parallel for collapse(2)
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < 100; ++j)
+ ;
+}
+
+// CHECK-LABEL: define internal void @_Z12fit_constantv.omp_outlined(
+// CHECK: call void @__kmpc_for_static_init_4(
+
+void wide_constant() {
+#pragma omp parallel for collapse(2)
+ for (int i = 0; i < 100000; ++i)
+ for (int j = 0; j < 100000; ++j)
+ ;
+}
+
+// CHECK-LABEL: define internal void @_Z13wide_constantv.omp_outlined(
+// CHECK: call void @__kmpc_for_static_init_8(
>From fd8e58f8d958026a46a94d5372186e5e339e9bb1 Mon Sep 17 00:00:00 2001
From: amtiwari <amtiwari at amd.com>
Date: Wed, 23 Sep 2026 07:10:07 -0400
Subject: [PATCH 2/3] Trigger CI
>From d565ee238ecd05398d62bf7cea51e4aa0713161d Mon Sep 17 00:00:00 2001
From: amtiwari <amtiwari at amd.com>
Date: Fri, 25 Sep 2026 05:16:09 -0400
Subject: [PATCH 3/3] nit
---
clang/lib/Sema/SemaOpenMP.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 865da6f5aa0fde..bf623257a50aa7 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -10381,7 +10381,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
auto BuildLastIteration = [&](unsigned Bits) -> ExprResult {
ExprResult Result;
- for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
+ for (unsigned Cnt : llvm::seq<unsigned>(NestedLoopCount)) {
Expr *N = IterSpaces[Cnt].NumIterations;
ExprResult Count = widenIterationCount(
Bits,
More information about the cfe-commits
mailing list