[flang-commits] [flang] [flang] Decouple HLFIR array expansion from optimization level (PR #233478)
via flang-commits
flang-commits at lists.llvm.org
Mon Oct 19 09:54:12 PDT 2026
https://github.com/jeanPerier updated https://github.com/llvm/llvm-project/pull/233478
>From b68fd2b2035853df3c436ef35e128246165df029 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Mon, 19 Oct 2026 08:04:29 -0700
Subject: [PATCH 1/2] [flang] Decouple HLFIR array expansion from optimization
level
Add useArrayRuntime to the pass pipeline configuration, preserving runtime use at O0 by default. Always attempt to inline scalar-to-array assignments, including host code at O0.
Update pipeline expectations and add coverage for broadcasts, array expressions, and reductions.
---
flang/include/flang/Optimizer/HLFIR/Passes.td | 7 ++-
flang/include/flang/Tools/CrossToolHelpers.h | 5 ++
flang/lib/Optimizer/Passes/Pipelines.cpp | 32 ++++--------
flang/test/Driver/array-runtime.f90 | 52 +++++++++++++++++++
.../test/Driver/mlir-debug-pass-pipeline.f90 | 5 ++
flang/test/Driver/mlir-omp-pass-pipeline.f90 | 6 +--
flang/test/Driver/mlir-pass-pipeline.f90 | 10 ++--
.../CUDA/scalar-to-array-assign-device-O0.cuf | 8 +--
...workdistribute-saxpy-and-scalar-assign.f90 | 17 +++---
.../OpenMP/workdistribute-scalar-assign.f90 | 13 ++---
10 files changed, 98 insertions(+), 57 deletions(-)
create mode 100644 flang/test/Driver/array-runtime.f90
diff --git a/flang/include/flang/Optimizer/HLFIR/Passes.td b/flang/include/flang/Optimizer/HLFIR/Passes.td
index 2835b3119fa2f..1f5cb03f03159 100644
--- a/flang/include/flang/Optimizer/HLFIR/Passes.td
+++ b/flang/include/flang/Optimizer/HLFIR/Passes.td
@@ -103,13 +103,12 @@ def InlineHLFIRAssign : Pass<"inline-hlfir-assign"> {
/*default=*/"false",
"Only inline assignments where RHS is a numeric or "
"logical scalar broadcast "
- "to an array LHS. Used at O0 to avoid runtime calls in "
- "device code without inlining all array assignments.">,
+ "to an array LHS, even when other array operations "
+ "are left to the runtime.">,
Option<"onlyCUDADeviceContext", "only-cuda-device-context",
"bool", /*default=*/"false",
"Only inline assignments in CUDA Fortran device "
- "code. Used at O0, where a module holds both host "
- "and device subprograms, to leave host code alone.">];
+ "code, leaving host code unchanged.">];
}
def InlineHLFIRCopy : Pass<"inline-hlfir-copy"> {
diff --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h
index b9add141663b9..d941aae37d6bd 100644
--- a/flang/include/flang/Tools/CrossToolHelpers.h
+++ b/flang/include/flang/Tools/CrossToolHelpers.h
@@ -114,11 +114,13 @@ class FlangEPCallBacks {
struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
explicit MLIRToLLVMPassPipelineConfig(llvm::OptimizationLevel level) {
OptLevel = level;
+ useArrayRuntime = level == llvm::OptimizationLevel::O0;
}
explicit MLIRToLLVMPassPipelineConfig(llvm::OptimizationLevel level,
const Fortran::frontend::CodeGenOptions &opts,
const Fortran::common::MathOptionsBase &mathOpts) {
OptLevel = level;
+ useArrayRuntime = level == llvm::OptimizationLevel::O0;
StackArrays = opts.StackArrays;
EnableSafeTrampoline = opts.EnableSafeTrampoline;
Underscoring = opts.Underscoring;
@@ -151,6 +153,9 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
}
llvm::OptimizationLevel OptLevel; ///< optimisation level
+ /// Prefer runtime calls over inline expansion of HLFIR array operations.
+ /// Scalar-to-array assignments are still inlined when possible.
+ bool useArrayRuntime = true;
bool StackArrays = false; ///< convert memory allocations to alloca.
bool EnableSafeTrampoline{false}; ///< Use runtime trampoline pool (W^X).
bool Underscoring = true; ///< add underscores to function names.
diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp
index 953104d0625b7..3257080575289 100644
--- a/flang/lib/Optimizer/Passes/Pipelines.cpp
+++ b/flang/lib/Optimizer/Passes/Pipelines.cpp
@@ -292,7 +292,7 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
config.invokeHLFIROptEarlyEPCallbacks(pm, optLevel);
- if (optLevel != llvm::OptimizationLevel::O0) {
+ if (!config.useArrayRuntime) {
addNestedPassToAllTopLevelOperations<PassConstructor>(
pm, hlfir::createExpressionSimplification);
addCanonicalizerPassWithoutRegionSimplification(pm);
@@ -305,7 +305,7 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
pm, hlfir::createInlineElementals);
addNestedPassToAllTopLevelOperations<PassConstructor>(
pm, hlfir::createSeparateAllocatableAssign);
- if (optLevel != llvm::OptimizationLevel::O0) {
+ if (!config.useArrayRuntime) {
addCanonicalizerPassWithoutRegionSimplification(pm);
pm.addPass(mlir::createCSEPass());
// Run SimplifyHLFIRIntrinsics pass late after CSE,
@@ -325,40 +325,26 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
addNestedPassToAllTopLevelOperations<PassConstructor>(
pm, hlfir::createInlineHLFIRCopy);
}
- } else if (config.EnableOpenMPIsTargetDevice &&
- enableOpenMP == EnableOpenMP::Full) {
- // At O0, only inline scalar-to-array broadcasts when compiling for an
- // OpenMP target device. This avoids emitting Fortran runtime calls
- // (e.g. _FortranAAssign) that use malloc/free in device code generated
- // by OpenMP target offloading. Restricting this to target-device
- // compilation preserves the runtime call on the host at -O0 so that a
- // line breakpoint on a scalar-to-array assignment hits once instead of
- // once per element.
+ } else {
+ // Always attempt to inline scalar-to-array assignments, even when other
+ // array operations are left to the runtime.
addNestedPassToAllTopLevelOperations(pm, [&]() {
return hlfir::createInlineHLFIRAssign({/*onlyScalarRHS=*/true});
});
- } else if (config.EnableCUDA) {
- // Same at O0 for CUDA Fortran device code, where the runtime call also
- // inflates the stack frame the device linker reserves for the kernel.
- // The module holds host code too, hence onlyCUDADeviceContext.
- addNestedPassToAllTopLevelOperations(pm, [&]() {
- return hlfir::createInlineHLFIRAssign(
- {/*onlyScalarRHS=*/true, /*onlyCUDADeviceContext=*/true});
- });
}
pm.addPass(hlfir::createLowerHLFIROrderedAssignments(
- {/*tryFusingAssignments=*/optLevel != llvm::OptimizationLevel::O0}));
+ {/*tryFusingAssignments=*/!config.useArrayRuntime}));
config.invokeHLFIROptLastEPCallbacks(pm, optLevel);
pm.addPass(hlfir::createLowerHLFIRIntrinsics());
hlfir::BufferizeHLFIROptions bufferizeOptions;
- // For opt-for-speed, avoid running any of the loops resulting
+ // When expanding array operations, avoid running any of the loops resulting
// from hlfir.elemental lowering, if the result is an empty array.
// This helps to avoid long running loops for elementals with
// shapes like (0, HUGE).
- if (optLevel != llvm::OptimizationLevel::O0)
+ if (!config.useArrayRuntime)
bufferizeOptions.optimizeEmptyElementals = true;
pm.addPass(hlfir::createBufferizeHLFIR(bufferizeOptions));
// Run hlfir.assign inlining again after BufferizeHLFIR,
@@ -368,7 +354,7 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm,
// TODO: we can remove the previous InlineHLFIRAssign, when
// FIR AliasAnalysis is good enough to say that a temporary
// array does not alias with any user object.
- if (optLevel != llvm::OptimizationLevel::O0)
+ if (!config.useArrayRuntime)
addNestedPassToAllTopLevelOperations<PassConstructor>(
pm, hlfir::createInlineHLFIRAssign);
pm.addPass(hlfir::createConvertHLFIRtoFIR());
diff --git a/flang/test/Driver/array-runtime.f90 b/flang/test/Driver/array-runtime.f90
new file mode 100644
index 0000000000000..ddfc33d0190d5
--- /dev/null
+++ b/flang/test/Driver/array-runtime.f90
@@ -0,0 +1,52 @@
+! Scalar broadcasts are expanded even at -O0. Other array assignments and
+! intrinsics retain the optimization-level-dependent default.
+! RUN: %flang_fc1 -emit-fir -O0 %s -o - | FileCheck %s --check-prefixes=ALL,RUNTIME
+! RUN: %flang_fc1 -emit-fir -O2 %s -o - | FileCheck %s --check-prefixes=ALL,EXPAND
+
+subroutine broadcast(x)
+ real :: x(:)
+ x = 1.
+end subroutine
+
+! ALL-LABEL: func{{(\.func)?}} @_QPbroadcast(
+! ALL-NOT: fir.call @_FortranAAssign
+! ALL: fir.do_loop
+! ALL-NOT: fir.call @_FortranAAssign
+! ALL: return
+
+subroutine array_copy(x, y)
+ real :: x(:), y(:)
+ x = y
+end subroutine
+
+! ALL-LABEL: func{{(\.func)?}} @_QParray_copy(
+! RUNTIME: fir.call @_FortranAAssign
+! EXPAND-NOT: fir.call @_FortranAAssign
+! EXPAND: fir.do_loop
+! EXPAND-NOT: fir.call @_FortranAAssign
+! ALL: return
+
+subroutine array_expression(x, y, z)
+ real :: x(:), y(:), z(:)
+ x = y + z
+end subroutine
+
+! ALL-LABEL: func{{(\.func)?}} @_QParray_expression(
+! RUNTIME: fir.call @_FortranAAssign
+! EXPAND-NOT: fir.call @_FortranAAssign
+! EXPAND: fir.do_loop
+! EXPAND: arith.addf
+! EXPAND-NOT: fir.call @_FortranAAssign
+! ALL: return
+
+function reduction(x)
+ real :: x(:), reduction
+ reduction = sum(x)
+end function
+
+! ALL-LABEL: func{{(\.func)?}} @_QPreduction(
+! RUNTIME: fir.call @_FortranASumReal4
+! EXPAND-NOT: fir.call @_FortranASum
+! EXPAND: fir.do_loop
+! EXPAND-NOT: fir.call @_FortranASum
+! ALL: return
diff --git a/flang/test/Driver/mlir-debug-pass-pipeline.f90 b/flang/test/Driver/mlir-debug-pass-pipeline.f90
index 1cc4fad4f76a4..25fdc4ee55780 100644
--- a/flang/test/Driver/mlir-debug-pass-pipeline.f90
+++ b/flang/test/Driver/mlir-debug-pass-pipeline.f90
@@ -31,18 +31,23 @@
! ALL-NEXT: 'fir.global' Pipeline
! ALL-NEXT: InlineElementals
! ALL-NEXT: SeparateAllocatableAssign
+! ALL-NEXT: InlineHLFIRAssign
! ALL-NEXT: 'func.func' Pipeline
! ALL-NEXT: InlineElementals
! ALL-NEXT: SeparateAllocatableAssign
+! ALL-NEXT: InlineHLFIRAssign
! ALL-NEXT: 'omp.declare_mapper' Pipeline
! ALL-NEXT: InlineElementals
! ALL-NEXT: SeparateAllocatableAssign
+! ALL-NEXT: InlineHLFIRAssign
! ALL-NEXT: 'omp.declare_reduction' Pipeline
! ALL-NEXT: InlineElementals
! ALL-NEXT: SeparateAllocatableAssign
+! ALL-NEXT: InlineHLFIRAssign
! ALL-NEXT: 'omp.private' Pipeline
! ALL-NEXT: InlineElementals
! ALL-NEXT: SeparateAllocatableAssign
+! ALL-NEXT: InlineHLFIRAssign
! ALL-NEXT: LowerHLFIROrderedAssignments
! ALL-NEXT: LowerHLFIRIntrinsics
! ALL-NEXT: BufferizeHLFIR
diff --git a/flang/test/Driver/mlir-omp-pass-pipeline.f90 b/flang/test/Driver/mlir-omp-pass-pipeline.f90
index 40e2c52b993a4..01eb1ee739126 100644
--- a/flang/test/Driver/mlir-omp-pass-pipeline.f90
+++ b/flang/test/Driver/mlir-omp-pass-pipeline.f90
@@ -14,7 +14,7 @@
! NO_OMP-NOT: AutomapToTargetDataPass
! NO_OMP-NOT: MapInfoFinalizationPass
! NO_OMP-NOT: GenericLoopConversionPass
-! NO_OMP-NOT: InlineHLFIRAssign
+! NO_OMP: InlineHLFIRAssign
! NO_OMP-NOT: LowerWorkshare
! NO_OMP-NOT: LowerWorkdistribute
! NO_OMP-NOT: SimdOnlyPass
@@ -30,7 +30,7 @@
! FULL: AutomapToTargetDataPass
! FULL: MapInfoFinalizationPass
! FULL: GenericLoopConversionPass
-! FULL-NOT: InlineHLFIRAssign
+! FULL: InlineHLFIRAssign
! FULL: LowerWorkshare
! FULL: LowerWorkdistribute
! FULL-NOT: SimdOnlyPass
@@ -47,7 +47,7 @@
! SIMD-NOT: AutomapToTargetDataPass
! SIMD-NOT: MapInfoFinalizationPass
! SIMD-NOT: GenericLoopConversionPass
-! SIMD-NOT: InlineHLFIRAssign
+! SIMD: InlineHLFIRAssign
! SIMD-NOT: LowerWorkshare
! SIMD-NOT: LowerWorkdistribute
! SIMD: SimdOnlyPass
diff --git a/flang/test/Driver/mlir-pass-pipeline.f90 b/flang/test/Driver/mlir-pass-pipeline.f90
index f7f4a29ab2de9..d91d0e0177bf3 100644
--- a/flang/test/Driver/mlir-pass-pipeline.f90
+++ b/flang/test/Driver/mlir-pass-pipeline.f90
@@ -9,11 +9,6 @@
end program
-! At -O0 on the host (no OpenMP target-device compilation), InlineHLFIRAssign
-! is no longer scheduled. See PR #197092 follow-up restricting the -O0 pass
-! to OpenMP target-device compilation.
-! O0-NOT: InlineHLFIRAssign
-
! ALL: Pass statistics report
! ALL: Fortran::lower::VerifierPass
@@ -37,22 +32,27 @@
! O2-NEXT: SimplifyHLFIRIntrinsics
! ALL: InlineElementals
! ALL-NEXT: SeparateAllocatableAssign
+! O0-NEXT: InlineHLFIRAssign
! ALL-NEXT:'func.func' Pipeline
! O2-NEXT: SimplifyHLFIRIntrinsics
! ALL: InlineElementals
! ALL-NEXT: SeparateAllocatableAssign
+! O0-NEXT: InlineHLFIRAssign
! ALL-NEXT:'omp.declare_mapper' Pipeline
! O2-NEXT: SimplifyHLFIRIntrinsics
! ALL: InlineElementals
! ALL-NEXT: SeparateAllocatableAssign
+! O0-NEXT: InlineHLFIRAssign
! ALL-NEXT:'omp.declare_reduction' Pipeline
! O2-NEXT: SimplifyHLFIRIntrinsics
! ALL: InlineElementals
! ALL-NEXT: SeparateAllocatableAssign
+! O0-NEXT: InlineHLFIRAssign
! ALL-NEXT:'omp.private' Pipeline
! O2-NEXT: SimplifyHLFIRIntrinsics
! ALL: InlineElementals
! ALL-NEXT: SeparateAllocatableAssign
+! O0-NEXT: InlineHLFIRAssign
! O2-NEXT: Canonicalizer
! O2-NEXT: CSE
! O2-NEXT: (S) {{.*}} num-cse'd
diff --git a/flang/test/Lower/CUDA/scalar-to-array-assign-device-O0.cuf b/flang/test/Lower/CUDA/scalar-to-array-assign-device-O0.cuf
index 7fa6291b93f33..ad9ded3ff81b7 100644
--- a/flang/test/Lower/CUDA/scalar-to-array-assign-device-O0.cuf
+++ b/flang/test/Lower/CUDA/scalar-to-array-assign-device-O0.cuf
@@ -1,6 +1,6 @@
! At -O0, a scalar-to-array broadcast must be inlined in device code to keep
-! _FortranAAssign out of the kernel's call graph. Host code keeps the call so
-! that a breakpoint on the assignment fires once, not once per element.
+! _FortranAAssign out of the kernel's call graph. Host code also inlines
+! scalar-to-array broadcasts.
! CUDA Fortran is enabled here by the .cuf suffix rather than -x cuda.
! RUN: %flang_fc1 -emit-fir -O0 %s -o - | FileCheck %s
@@ -41,4 +41,6 @@ end module
! CHECK-NOT: fir.call @_FortranAAssign
! CHECK-LABEL: func.func @_QMmPhost_broadcast
-! CHECK: fir.call @_FortranAAssign
+! CHECK-NOT: fir.call @_FortranAAssign
+! CHECK: fir.do_loop
+! CHECK-NOT: fir.call @_FortranAAssign
diff --git a/flang/test/Lower/OpenMP/workdistribute-saxpy-and-scalar-assign.f90 b/flang/test/Lower/OpenMP/workdistribute-saxpy-and-scalar-assign.f90
index 09e3375efa487..8e005ddd9dea1 100644
--- a/flang/test/Lower/OpenMP/workdistribute-saxpy-and-scalar-assign.f90
+++ b/flang/test/Lower/OpenMP/workdistribute-saxpy-and-scalar-assign.f90
@@ -60,20 +60,15 @@ subroutine teams_workdistribute()
!$omp end teams workdistribute
end subroutine teams_workdistribute
-! At -O0 host (no -fopenmp-is-target-device):
-! - target teams workdistribute inlines both the saxpy and the scalar
-! broadcast via workdistributeRuntimeCallLower, so no _FortranAAssign
-! runtime call appears.
-! - teams workdistribute (no target) keeps the saxpy result write-back
-! and the scalar broadcast as _FortranAAssign runtime calls. The
-! two calls correspond to source lines 50 (saxpy) and 58 (scalar
-! broadcast) respectively; the ordered CHECK-O0 lines below match
-! each region in source order so neither expectation can accidentally
-! match the other assignment.
+! At -O0, target teams workdistribute expands both assignments. On the host,
+! the saxpy result write-back still uses the runtime, but the scalar broadcast
+! is inlined and workshared.
! CHECK-O0-LABEL: func @_QPtarget_teams_workdistribute
! CHECK-O0-NOT: fir.call @_FortranAAssign
! CHECK-O0-LABEL: func @_QPteams_workdistribute
! CHECK-O0: omp.wsloop
! CHECK-O0: fir.call @_FortranAAssignSimple({{.*}}%c50_i32)
-! CHECK-O0: fir.call @_FortranAAssign({{.*}}%c58_i32)
+! CHECK-O0-NOT: fir.call @_FortranAAssign
+! CHECK-O0: omp.wsloop
+! CHECK-O0-NOT: fir.call @_FortranAAssign
diff --git a/flang/test/Lower/OpenMP/workdistribute-scalar-assign.f90 b/flang/test/Lower/OpenMP/workdistribute-scalar-assign.f90
index 68c9060ee9bd6..ccc5f13bbe67b 100644
--- a/flang/test/Lower/OpenMP/workdistribute-scalar-assign.f90
+++ b/flang/test/Lower/OpenMP/workdistribute-scalar-assign.f90
@@ -35,16 +35,13 @@ subroutine teams_workdistribute_scalar_assign()
end subroutine teams_workdistribute_scalar_assign
-! At -O0 host (no -fopenmp-is-target-device), target teams workdistribute
-! still goes through workdistributeRuntimeCallLower, so the scalar
-! broadcast inside the target region is inlined and workshared, with no
-! _FortranAAssign runtime call.
+! At -O0, scalar broadcasts are inlined and workshared on both host and device.
! CHECK-O0-LABEL: func @_QPtarget_teams_workdistribute_scalar_assign
+! CHECK-O0-NOT: fir.call @_FortranAAssign
! CHECK-O0: omp.wsloop
! CHECK-O0-NOT: fir.call @_FortranAAssign
-! At -O0 host, teams workdistribute (no target) does not inline the
-! scalar broadcast after PR #201774, so the assignment remains a
-! _FortranAAssign runtime call. This pins the plain host -O0 behavior.
! CHECK-O0-LABEL: func @_QPteams_workdistribute_scalar_assign
-! CHECK-O0: fir.call @_FortranAAssign
+! CHECK-O0-NOT: fir.call @_FortranAAssign
+! CHECK-O0: omp.wsloop
+! CHECK-O0-NOT: fir.call @_FortranAAssign
>From 63f0bd44ed5c9df99b706d2d83663756a5c364d7 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Mon, 19 Oct 2026 09:53:47 -0700
Subject: [PATCH 2/2] test updates
---
.../parallel-private-reduction-worstcase.f90 | 96 ++++++++++++-------
.../Integration/OpenMP/private-global.f90 | 16 ++--
flang/test/Integration/prefetch.f90 | 1 -
.../Lower/scalar-to-array-assign-host-O0.f90 | 22 +++--
4 files changed, 79 insertions(+), 56 deletions(-)
diff --git a/flang/test/Integration/OpenMP/parallel-private-reduction-worstcase.f90 b/flang/test/Integration/OpenMP/parallel-private-reduction-worstcase.f90
index ea52c2a2b5bb8..4f86c590b7e95 100644
--- a/flang/test/Integration/OpenMP/parallel-private-reduction-worstcase.f90
+++ b/flang/test/Integration/OpenMP/parallel-private-reduction-worstcase.f90
@@ -117,44 +117,62 @@ subroutine worst_case(a, b, c, d)
! [malloc and assign the default value to the reduction variable]
! CHECK: br label %omp.reduction.neutral46
-! CHECK: omp.reduction.neutral46: ; preds = %omp.reduction.neutral44, %omp.reduction.neutral45
+! CHECK: omp.reduction.neutral46: ; preds = %omp.reduction.neutral47, %omp.reduction.neutral45
+! [loop assigning the neutral value to each element]
+! CHECK-NEXT: %{{.*}} = phi i64
+! CHECK-NEXT: %{{.*}} = phi i64
+! CHECK: br i1 %{{.*}}, label %omp.reduction.neutral47, label %omp.reduction.neutral48
+
+! CHECK: omp.reduction.neutral48: ; preds = %omp.reduction.neutral46
+! CHECK: br label %omp.reduction.neutral49
+
+! CHECK: omp.reduction.neutral49: ; preds = %omp.reduction.neutral44, %omp.reduction.neutral48
! CHECK-NEXT: br label %omp.region.cont43
-! CHECK: omp.region.cont43: ; preds = %omp.reduction.neutral46
+! CHECK: omp.region.cont43: ; preds = %omp.reduction.neutral49
! CHECK-NEXT: %{{.*}} = phi ptr
-! CHECK-NEXT: br label %omp.reduction.neutral48
+! CHECK-NEXT: br label %omp.reduction.neutral51
-! CHECK: omp.reduction.neutral48: ; preds = %omp.region.cont43
+! CHECK: omp.reduction.neutral51: ; preds = %omp.region.cont43
! [start of reduction initialization region]
! [null check:]
-! CHECK: br i1 %{{.*}}, label %omp.reduction.neutral49, label %omp.reduction.neutral50
+! CHECK: br i1 %{{.*}}, label %omp.reduction.neutral52, label %omp.reduction.neutral53
-! CHECK: omp.reduction.neutral50: ; preds = %omp.reduction.neutral48
+! CHECK: omp.reduction.neutral53: ; preds = %omp.reduction.neutral51
! [malloc and assign the default value to the reduction variable]
-! CHECK: br label %omp.reduction.neutral51
+! CHECK: br label %omp.reduction.neutral54
+
+! CHECK: omp.reduction.neutral54: ; preds = %omp.reduction.neutral55, %omp.reduction.neutral53
+! [loop assigning the neutral value to each element]
+! CHECK-NEXT: %{{.*}} = phi i64
+! CHECK-NEXT: %{{.*}} = phi i64
+! CHECK: br i1 %{{.*}}, label %omp.reduction.neutral55, label %omp.reduction.neutral56
+
+! CHECK: omp.reduction.neutral56: ; preds = %omp.reduction.neutral54
+! CHECK: br label %omp.reduction.neutral57
-! CHECK: omp.reduction.neutral51: ; preds = %omp.reduction.neutral49, %omp.reduction.neutral50
-! CHECK-NEXT: br label %omp.region.cont47
+! CHECK: omp.reduction.neutral57: ; preds = %omp.reduction.neutral52, %omp.reduction.neutral56
+! CHECK-NEXT: br label %omp.region.cont50
-! CHECK: omp.region.cont47: ; preds = %omp.reduction.neutral51
+! CHECK: omp.region.cont50: ; preds = %omp.reduction.neutral57
! CHECK-NEXT: %{{.*}} = phi ptr
-! CHECK-NEXT: br label %omp.par.region53
+! CHECK-NEXT: br label %omp.par.region59
-! CHECK: omp.par.region53: ; preds = %omp.region.cont47
-! CHECK-NEXT: br label %omp.par.region54
+! CHECK: omp.par.region59: ; preds = %omp.region.cont50
+! CHECK-NEXT: br label %omp.par.region60
-! CHECK: omp.par.region54: ; preds = %omp.par.region53
+! CHECK: omp.par.region60: ; preds = %omp.par.region59
! [call SUM runtime function]
! [if (sum(a) == 1)]
-! CHECK: br i1 %{{.*}}, label %omp.par.region55, label %omp.par.region56
+! CHECK: br i1 %{{.*}}, label %omp.par.region61, label %omp.par.region62
-! CHECK: omp.par.region56: ; preds = %omp.par.region54
-! CHECK-NEXT: br label %omp.par.region57
+! CHECK: omp.par.region62: ; preds = %omp.par.region60
+! CHECK-NEXT: br label %omp.par.region63
-! CHECK: omp.par.region57: ; preds = %omp.par.region56
-! CHECK-NEXT: br label %omp.region.cont52
+! CHECK: omp.par.region63: ; preds = %omp.par.region62
+! CHECK-NEXT: br label %omp.region.cont58
-! CHECK: omp.region.cont52: ; preds = %omp.par.region57
+! CHECK: omp.region.cont58: ; preds = %omp.par.region63
! [omp parallel region done, call into the runtime to complete reduction]
! CHECK: %[[VAL_233:.*]] = call i32 @__kmpc_reduce(
! CHECK: switch i32 %[[VAL_233]], label %reduce.finalize [
@@ -162,16 +180,16 @@ subroutine worst_case(a, b, c, d)
! CHECK-NEXT: i32 2, label %reduce.switch.atomic
! CHECK-NEXT: ]
-! CHECK: reduce.switch.atomic: ; preds = %omp.region.cont52
+! CHECK: reduce.switch.atomic: ; preds = %omp.region.cont58
! CHECK-NEXT: unreachable
-! CHECK: reduce.switch.nonatomic: ; preds = %omp.region.cont52
+! CHECK: reduce.switch.nonatomic: ; preds = %omp.region.cont58
! CHECK-NEXT: %[[red_private_value_0:.*]] = load ptr, ptr %{{.*}}, align 8
! CHECK-NEXT: br label %omp.reduction.nonatomic.body
! [various blocks implementing the reduction]
-! CHECK: omp.region.cont62: ; preds =
+! CHECK: omp.region.cont68: ; preds =
! CHECK-NEXT: %{{.*}} = phi ptr
! CHECK-NEXT: call void @__kmpc_end_reduce(
! CHECK-NEXT: br label %reduce.finalize
@@ -188,30 +206,38 @@ subroutine worst_case(a, b, c, d)
! CHECK: omp.reduction.cleanup: ; preds = %.fini
! [null check]
-! CHECK: br i1 %{{.*}}, label %omp.reduction.cleanup68, label %omp.reduction.cleanup69
+! CHECK: br i1 %{{.*}}, label %omp.reduction.cleanup74, label %omp.reduction.cleanup75
-! CHECK: omp.reduction.cleanup69: ; preds = %omp.reduction.cleanup68, %omp.reduction.cleanup
-! CHECK-NEXT: br label %omp.region.cont67
+! CHECK: omp.reduction.cleanup75: ; preds = %omp.reduction.cleanup74, %omp.reduction.cleanup
+! CHECK-NEXT: br label %omp.region.cont73
-! CHECK: omp.region.cont67: ; preds = %omp.reduction.cleanup69
+! CHECK: omp.region.cont73: ; preds = %omp.reduction.cleanup75
! CHECK-NEXT: %{{.*}} = load ptr, ptr
-! CHECK-NEXT: br label %omp.reduction.cleanup71
+! CHECK-NEXT: br label %omp.reduction.cleanup77
-! CHECK: omp.reduction.cleanup71: ; preds = %omp.region.cont67
+! CHECK: omp.reduction.cleanup77: ; preds = %omp.region.cont73
! [null check]
-! CHECK: br i1 %{{.*}}, label %omp.reduction.cleanup72, label %omp.reduction.cleanup73
+! CHECK: br i1 %{{.*}}, label %omp.reduction.cleanup78, label %omp.reduction.cleanup79
-! CHECK: omp.par.region55: ; preds = %omp.par.region54
+! CHECK: omp.par.region61: ; preds = %omp.par.region60
! CHECK-NEXT: call void @_FortranAStopStatement
! CHECK-NEXT: unreachable
-! CHECK: omp.reduction.neutral49: ; preds = %omp.reduction.neutral48
+! CHECK: omp.reduction.neutral55: ; preds = %omp.reduction.neutral54
+! CHECK: store float 0.000000e+00, ptr %{{.*}}, align 4
+! CHECK: br label %omp.reduction.neutral54
+
+! CHECK: omp.reduction.neutral52: ; preds = %omp.reduction.neutral51
! [source length was zero: finish initializing array]
-! CHECK: br label %omp.reduction.neutral51
+! CHECK: br label %omp.reduction.neutral57
+
+! CHECK: omp.reduction.neutral47: ; preds = %omp.reduction.neutral46
+! CHECK: store float 0.000000e+00, ptr %{{.*}}, align 4
+! CHECK: br label %omp.reduction.neutral46
! CHECK: omp.reduction.neutral44: ; preds = %omp.reduction.neutral
! [source length was zero: finish initializing array]
-! CHECK: br label %omp.reduction.neutral46
+! CHECK: br label %omp.reduction.neutral49
! CHECK: omp.private.copy41: ; preds = %omp.private.copy40, %omp.private.copy37
! [source length was non-zero: call assign runtime]
@@ -247,5 +273,5 @@ subroutine worst_case(a, b, c, d)
! [var extent was non-zero: malloc a private array]
! CHECK: br label %omp.private.init5
-! CHECK: omp.par.exit.exitStub: ; preds = %omp.region.cont77
+! CHECK: omp.par.exit.exitStub: ; preds = %omp.region.cont83
! CHECK-NEXT: ret void
diff --git a/flang/test/Integration/OpenMP/private-global.f90 b/flang/test/Integration/OpenMP/private-global.f90
index 56310a3ca21a4..2d1e63eefd8ca 100644
--- a/flang/test/Integration/OpenMP/private-global.f90
+++ b/flang/test/Integration/OpenMP/private-global.f90
@@ -22,17 +22,13 @@ program bug
! and no heap allocation for the private itself.
! CHECK: %[[PRIV_TABLE:.*]] = alloca [10 x i32], align 4
-! check that we use the private copy of table for the assignment: its data
-! pointer is placed in a descriptor which -- threaded through the store and
-! memcpy below -- is the destination handed to the runtime assign.
-! CHECK: omp.par.region1:
-! CHECK: %[[TABLE_DESC:.*]] = insertvalue {{.*}}, ptr %[[PRIV_TABLE]], 0
-! CHECK: store {{.*}} %[[TABLE_DESC]], ptr %[[DESC_MEM:.*]], align
-! CHECK: call void @llvm.memcpy.p0.p0.i32(ptr %[[ASSIGN_DST:.*]], ptr %[[DESC_MEM]], i32 {{.*}}, i1 false)
-! CHECK: call void @_FortranAAssign(ptr %[[ASSIGN_DST]],
-
! check that we use the private copy of table for table/=50
-! CHECK: omp.par.region3:
+! CHECK: omp.par.region7:
! CHECK: %[[ELT_PTR:.*]] = getelementptr {{.*}} i32, ptr %[[PRIV_TABLE]], i64 %{{.*}}
! CHECK: %[[ELT:.*]] = load i32, ptr %[[ELT_PTR]]
! CHECK: icmp ne i32 %[[ELT]], 50
+
+! check that the inline assignment loop stores into the private copy of table
+! CHECK: omp.par.region3:
+! CHECK: %[[ASSIGN_ELT_PTR:.*]] = getelementptr {{.*}} i32, ptr %[[PRIV_TABLE]], i64 %{{.*}}
+! CHECK-NEXT: store i32 50, ptr %[[ASSIGN_ELT_PTR]], align 4
diff --git a/flang/test/Integration/prefetch.f90 b/flang/test/Integration/prefetch.f90
index c015b6736972a..76227caf02b43 100644
--- a/flang/test/Integration/prefetch.f90
+++ b/flang/test/Integration/prefetch.f90
@@ -13,7 +13,6 @@
!===============================================================================
subroutine test_prefetch_01()
- ! LLVM: {{.*}} = alloca i32, i64 1, align 4
! LLVM: %[[VAR_J:.*]] = alloca i32, i64 1, align 4
! LLVM: %[[VAR_I:.*]] = alloca i32, i64 1, align 4
! LLVM: %[[VAR_A:.*]] = alloca [256 x i32], i64 1, align 4
diff --git a/flang/test/Lower/scalar-to-array-assign-host-O0.f90 b/flang/test/Lower/scalar-to-array-assign-host-O0.f90
index 88d4344da6f2b..a7a40af6b5367 100644
--- a/flang/test/Lower/scalar-to-array-assign-host-O0.f90
+++ b/flang/test/Lower/scalar-to-array-assign-host-O0.f90
@@ -1,17 +1,19 @@
-! Regression test for the follow-up to PR llvm/llvm-project#197092.
-!
-! At -O0 on the host (no OpenMP target-device compilation), a scalar-to-array
-! broadcast assignment must lower to a Fortran runtime call
-! (_FortranAAssign), not to an inline assignment loop. Lowering it inline
-! at -O0 caused -g line breakpoints to hit once per array element instead
-! of once.
+! Scalar-to-array broadcast assignments are expanded inline even at -O0
+! on the host (no OpenMP target-device compilation).
-! RUN: %flang_fc1 -emit-fir -O0 %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-fir -O0 %s -o - | FileCheck %s --implicit-check-not=_FortranAAssign
! CHECK-LABEL: func @_QPhost_scalar_broadcast
subroutine host_scalar_broadcast(arr)
integer :: arr(4)
- ! CHECK: fir.call @_FortranAAssign
- ! CHECK-NOT: fir.do_loop
+ ! CHECK-DAG: %[[ONE:.*]] = arith.constant 1 : index
+ ! CHECK-DAG: %[[VALUE:.*]] = arith.constant 11 : i32
+ ! CHECK-DAG: %[[EXTENT:.*]] = arith.constant 4 : index
+ ! CHECK: %[[SHAPE:.*]] = fir.shape %[[EXTENT]]
+ ! CHECK: %[[ARR:.*]] = fir.declare %arg0(%[[SHAPE]])
+ ! CHECK: fir.do_loop %[[INDEX:.*]] = %[[ONE]] to %[[EXTENT]] step %[[ONE]] unordered {
+ ! CHECK-NEXT: %[[ELEMENT:.*]] = fir.array_coor %[[ARR]](%[[SHAPE]]) %[[INDEX]]
+ ! CHECK-NEXT: fir.store %[[VALUE]] to %[[ELEMENT]] : !fir.ref<i32>
+ ! CHECK-NEXT: }
arr = 11
end subroutine
More information about the flang-commits
mailing list