https://github.com/loopacino created https://github.com/llvm/llvm-project/pull/225612
`collapse` used to build both a 32-bit and a 64-bit trip-count, then keep one. This patch does the same in `checkOpenMPLoop`: If we know 32-bit is enough, build only 32-bit. Else build 64-bit first. Build 32-bit only when the product is a compile-time constant and fits. Origin: `flatten` already builds only the width it keeps. >From 3a6a435bfa37bcb9676c61debc99899745a1eae3 Mon Sep 17 00:00:00 2001 From: amtiwari <[email protected]> Date: Wed, 23 Sep 2026 02:55:31 -0400 Subject: [PATCH] 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 88b642b73895f..865da6f5aa0fd 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 0000000000000..3e1e5c93a4da0 --- /dev/null +++ b/clang/test/OpenMP/collapse_iv_width_codegen.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -verify -fopenmp -std=c++20 -Wno-bit-int-extension \ +// RUN: -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( _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
