[flang-commits] [flang] 79ec8e3 - [Flang][OpenMP] Remove the DeleteUnreachableTargets pass (#214183)
via flang-commits
flang-commits at lists.llvm.org
Wed Aug 19 05:15:35 PDT 2026
Author: Sergio Afonso
Date: 2026-08-19T13:15:15+01:00
New Revision: 79ec8e363a22159ed311193a47091e17a5ef1dc2
URL: https://github.com/llvm/llvm-project/commit/79ec8e363a22159ed311193a47091e17a5ef1dc2
DIFF: https://github.com/llvm/llvm-project/commit/79ec8e363a22159ed311193a47091e17a5ef1dc2.diff
LOG: [Flang][OpenMP] Remove the DeleteUnreachableTargets pass (#214183)
The `DeleteUnreachableTargets` pass was initially added to work around a
problem caused by the interaction between the function filtering and
host op filtering passes and generic MLIR optimizations.
Specifically, by running function and host op filtering before these
optimizations, we would lose the ability to detect unreachable
`omp.target` operations when compiling for the device. This would cause
GPU kernels being created for them, for which no host counterpart
existed.
By now having moved both passes towards the end of the compilation
pipeline, after FIR to LLVM lowering, removal of unreachable host and
device code is no longer impacted by them. This makes the
`DeleteUnreachableTargets` pass redundant.
Added:
flang/test/Integration/OpenMP/target-dead-code.f90
Modified:
flang/include/flang/Optimizer/OpenMP/Passes.td
flang/lib/Optimizer/OpenMP/CMakeLists.txt
flang/lib/Optimizer/Passes/Pipelines.cpp
Removed:
flang/lib/Optimizer/OpenMP/DeleteUnreachableTargets.cpp
flang/test/Lower/OpenMP/target-dead-code.f90
flang/test/Transforms/OpenMP/delete-unreachable-targets.mlir
################################################################################
diff --git a/flang/include/flang/Optimizer/OpenMP/Passes.td b/flang/include/flang/Optimizer/OpenMP/Passes.td
index b81ff842948c3..08272d24252ee 100644
--- a/flang/include/flang/Optimizer/OpenMP/Passes.td
+++ b/flang/include/flang/Optimizer/OpenMP/Passes.td
@@ -35,18 +35,6 @@ def MapsForPrivatizedSymbolsPass
let dependentDialects = ["mlir::omp::OpenMPDialect"];
}
-def DeleteUnreachableTargetsPass
- : Pass<"omp-delete-unreachable-targets", "mlir::ModuleOp"> {
- let summary = "Deletes OpenMP target operations in unreachable code";
- let description = [{
- Identifies and removes OpenMP target operations that reside in unreachable
- code (e.g., inside if(.false.) blocks). This ensures consistency between
- host and device compilation by preventing unreachable targets from being
- processed on the device side.
- }];
- let dependentDialects = ["mlir::omp::OpenMPDialect"];
-}
-
def DoConcurrentConversionPass : Pass<"omp-do-concurrent-conversion", "mlir::ModuleOp"> {
let summary = "Map `DO CONCURRENT` loops to OpenMP worksharing loops.";
diff --git a/flang/lib/Optimizer/OpenMP/CMakeLists.txt b/flang/lib/Optimizer/OpenMP/CMakeLists.txt
index 9c14716f4f06a..f29ba86a8a28c 100644
--- a/flang/lib/Optimizer/OpenMP/CMakeLists.txt
+++ b/flang/lib/Optimizer/OpenMP/CMakeLists.txt
@@ -6,7 +6,6 @@ add_flang_library(FlangOpenMPTransforms
GenericLoopConversion.cpp
MapsForPrivatizedSymbols.cpp
MapInfoFinalization.cpp
- DeleteUnreachableTargets.cpp
LowerWorkdistribute.cpp
LowerWorkshare.cpp
LowerNontemporal.cpp
diff --git a/flang/lib/Optimizer/OpenMP/DeleteUnreachableTargets.cpp b/flang/lib/Optimizer/OpenMP/DeleteUnreachableTargets.cpp
deleted file mode 100644
index de2b226f85f23..0000000000000
--- a/flang/lib/Optimizer/OpenMP/DeleteUnreachableTargets.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-//===- DeleteUnreachableTargets.cpp --------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This pass removes OpenMP target operations that are in unreachable code.
-// This ensures host and device compilation have consistent target regions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "flang/Optimizer/OpenMP/Passes.h"
-#include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
-#include "mlir/Analysis/DataFlow/Utils.h"
-#include "mlir/Analysis/DataFlowFramework.h"
-#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
-#include "mlir/IR/BuiltinOps.h"
-#include "mlir/Pass/Pass.h"
-#include "mlir/Support/LLVM.h"
-#include "llvm/ADT/SmallVector.h"
-
-namespace flangomp {
-#define GEN_PASS_DEF_DELETEUNREACHABLETARGETSPASS
-#include "flang/Optimizer/OpenMP/Passes.h.inc"
-} // namespace flangomp
-
-using namespace mlir;
-
-namespace {
-
-/// Check if an operation is unreachable using DeadCodeAnalysis.
-static bool isOperationUnreachable(Operation *op, DataFlowSolver &solver) {
- Block *block = op->getBlock();
- if (!block)
- return false;
-
- // Query DeadCodeAnalysis to check if the block is live (reachable).
- ProgramPoint *point = solver.getProgramPointBefore(block);
- const dataflow::Executable *executable =
- solver.lookupState<dataflow::Executable>(point);
-
- return (executable && !executable->isLive());
-}
-
-class DeleteUnreachableTargetsPass
- : public flangomp::impl::DeleteUnreachableTargetsPassBase<
- DeleteUnreachableTargetsPass> {
-public:
- DeleteUnreachableTargetsPass() = default;
-
- void runOnOperation() override {
- auto module = getOperation();
- DataFlowSolver solver;
- dataflow::loadBaselineAnalyses(solver);
-
- if (failed(solver.initializeAndRun(module))) {
- signalPassFailure();
- return;
- }
-
- // Collect unreachable target operations
- SmallVector<omp::TargetOp> unreachableTargets;
- module.walk([&](omp::TargetOp targetOp) {
- if (isOperationUnreachable(targetOp.getOperation(), solver))
- unreachableTargets.push_back(targetOp);
- });
-
- // Delete unreachable target operations
- for (omp::TargetOp targetOp : unreachableTargets)
- targetOp->erase();
- }
-};
-
-} // namespace
diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp
index 2812d23bbec73..cc61237760178 100644
--- a/flang/lib/Optimizer/Passes/Pipelines.cpp
+++ b/flang/lib/Optimizer/Passes/Pipelines.cpp
@@ -372,9 +372,6 @@ void createOpenMPFIRPassPipeline(mlir::PassManager &pm,
pm.addPass(flangomp::createAutomapToTargetDataPass());
pm.addPass(flangomp::createMapInfoFinalizationPass());
- // Delete unreachable target operations before FunctionFilteringPass
- // extracts them.
- pm.addPass(flangomp::createDeleteUnreachableTargetsPass());
pm.addPass(flangomp::createGenericLoopConversionPass());
}
diff --git a/flang/test/Integration/OpenMP/target-dead-code.f90 b/flang/test/Integration/OpenMP/target-dead-code.f90
new file mode 100644
index 0000000000000..cdcf7d39bb67c
--- /dev/null
+++ b/flang/test/Integration/OpenMP/target-dead-code.f90
@@ -0,0 +1,271 @@
+!===----------------------------------------------------------------------===!
+! This directory can be used to add Integration tests involving multiple
+! stages of the compiler (for eg. from Fortran to LLVM IR). It should not
+! contain executable tests. We should only add tests here sparingly and only
+! if there is no other way to test. Repeat this message in each test that is
+! added to this directory and sub-directories.
+!===----------------------------------------------------------------------===!
+
+! RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | tco -test-gen | FileCheck %s --check-prefixes=HOST,ALL
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-is-target-device %s -o - | tco -test-gen | FileCheck %s --check-prefixes=DEVICE,ALL
+
+! Test that OpenMP target regions in dead code are deleted from both host and
+! target device.
+
+! Test 1: if (.false.) with target - target should be deleted
+! HOST-LABEL: llvm.func @_QPtest_dead_simple
+! HOST-NOT: omp.target
+! HOST: llvm.return
+! DEVICE-NOT: llvm.func @_QPtest_dead_simple
+subroutine test_dead_simple()
+ real :: v
+ if (.false.) then
+ !$omp target map(tofrom:v)
+ v = 1.0
+ !$omp end target
+ end if
+end subroutine
+
+! Test 2: Live target - should remain
+! ALL-LABEL: llvm.func @_QPtest_live_simple
+! ALL: omp.target
+! ALL: llvm.return
+subroutine test_live_simple()
+ real :: v
+ if (.true.) then
+ !$omp target map(tofrom:v)
+ v = 2.0
+ !$omp end target
+ end if
+end subroutine
+
+! Test 3: Mixed dead and live
+! ALL-LABEL: llvm.func @_QPtest_mixed
+subroutine test_mixed()
+ real :: v
+ ! Dead - should be deleted
+ ! ALL-NOT: {{.*}} = llvm.mlir.constant(3.0{{.*}} : f32)
+ if (.false.) then
+ !$omp target map(tofrom:v)
+ v = 3.0
+ !$omp end target
+ end if
+
+ ! Live - should remain
+ !$omp target map(tofrom:v)
+ ! ALL: omp.target
+ ! ALL: {{.*}} = llvm.mlir.constant(4.0{{.*}} : f32)
+ v = 4.0
+ !$omp end target
+
+ ! Expect exactly 1 omp.target in function
+ ! ALL-NOT: omp.target
+ ! ALL: llvm.return
+end subroutine
+
+! Test 4: Nested - outer false, target should be deleted
+! HOST-LABEL: llvm.func @_QPtest_nested_outer_false
+! HOST-NOT: omp.target
+! HOST: llvm.return
+! DEVICE-NOT: llvm.func @_QPtest_nested_outer_false
+subroutine test_nested_outer_false()
+ real :: v
+ if (.false.) then
+ if (.true.) then
+ !$omp target map(tofrom:v)
+ v = 5.0
+ !$omp end target
+ end if
+ end if
+end subroutine
+
+! Test 5: Nested - inner false, target should be deleted
+! HOST-LABEL: llvm.func @_QPtest_nested_inner_false
+! HOST-NOT: omp.target
+! HOST: llvm.return
+! DEVICE-NOT: llvm.func @_QPtest_nested_inner_false
+subroutine test_nested_inner_false()
+ real :: v
+ if (.true.) then
+ if (.false.) then
+ !$omp target map(tofrom:v)
+ v = 6.0
+ !$omp end target
+ end if
+ end if
+end subroutine
+
+! Test 6: Nested - both true, target should remain
+! ALL-LABEL: llvm.func @_QPtest_nested_both_true
+! ALL: omp.target
+! ALL: llvm.return
+subroutine test_nested_both_true()
+ real :: v
+ if (.true.) then
+ if (.true.) then
+ !$omp target map(tofrom:v)
+ v = 7.0
+ !$omp end target
+ end if
+ end if
+end subroutine
+
+! Test 7: Multiple dead targets in dead branch - all should be deleted
+! HOST-LABEL: llvm.func @_QPtest_multiple_dead_targets
+! HOST-NOT: omp.target
+! HOST: llvm.return
+! DEVICE-NOT: llvm.func @_QPtest_multiple_dead_targets
+subroutine test_multiple_dead_targets()
+ real :: v
+ if (.false.) then
+ !$omp target map(tofrom:v)
+ v = 8.0
+ !$omp end target
+ !$omp target map(tofrom:v)
+ v = 9.0
+ !$omp end target
+ !$omp target map(tofrom:v)
+ v = 10.0
+ !$omp end target
+ end if
+end subroutine
+
+! Test 8: Parameter constant - target should be deleted
+! HOST-LABEL: llvm.func @_QPtest_parameter
+! HOST-NOT: omp.target
+! HOST: llvm.return
+! DEVICE-NOT: llvm.func @_QPtest_parameter
+subroutine test_parameter()
+ real :: v
+ logical, parameter :: DEAD = .false.
+ if (DEAD) then
+ !$omp target map(tofrom:v)
+ v = 11.0
+ !$omp end target
+ end if
+end subroutine
+
+! Test 9: Unused nested subroutine - target should be deleted
+! HOST-LABEL: llvm.func @_QPtest_outer
+! HOST-NOT: omp.target
+! HOST: llvm.return
+! DEVICE-NOT: llvm.func @_QPtest_outer
+subroutine test_outer
+ implicit none
+contains
+ subroutine unused_sub()
+ real :: v
+ !$omp target map(tofrom: v)
+ v = 12.0
+ !$omp end target
+ end subroutine
+end subroutine
+
+! Test 10: if (.false.) with else - then-branch target deleted, else-branch remains
+! ALL-LABEL: llvm.func @_QPtest_if_else_false
+subroutine test_if_else_false()
+ real :: v
+ ! Dead then-branch - target should be deleted
+ ! ALL-NOT: {{.*}} = llvm.mlir.constant(1.3{{.*}}e+01 : f32)
+ if (.false.) then
+ !$omp target map(tofrom:v)
+ v = 13.0
+ !$omp end target
+ else
+ ! Live else-branch - target should remain
+ !$omp target map(tofrom:v)
+ ! ALL: omp.target
+ ! ALL: {{.*}} = llvm.mlir.constant(1.4{{.*}}e+01 : f32)
+ v = 14.0
+ !$omp end target
+ end if
+ ! Expect exactly 1 omp.target in function
+ ! ALL-NOT: omp.target
+ ! ALL: llvm.return
+end subroutine
+
+! Test 11: Runtime condition - target should remain unchanged
+! ALL-LABEL: llvm.func @_QPtest_runtime_condition
+! ALL: omp.target
+! ALL: llvm.return
+subroutine test_runtime_condition(cond)
+ logical, intent(in) :: cond
+ real :: v
+ if (cond) then
+ !$omp target map(tofrom:v)
+ v = 15.0
+ !$omp end target
+ end if
+end subroutine
+
+! Test 12: Target nested in unreachable block - target should be deleted
+! ALL-LABEL: llvm.func @_QPtest_nested_in_unreachable_block
+subroutine test_nested_in_unreachable_block()
+ real :: v
+ go to 10
+ ! Unreachable block: even though condition is .true., the block itself is dead
+ ! ALL-NOT: {{.*}} = llvm.mlir.constant(1.6{{.*}}e+01 : f32)
+ if (.true.) then
+ !$omp target map(tofrom:v)
+ v = 16.0
+ !$omp end target
+ end if
+10 continue
+ ! Reachable - target should remain
+ !$omp target map(tofrom:v)
+ ! ALL: omp.target
+ ! ALL: {{.*}} = llvm.mlir.constant(1.7{{.*}}e+01 : f32)
+ v = 17.0
+ !$omp end target
+ ! Expect exactly 1 omp.target in function
+ ! ALL-NOT: omp.target
+ ! ALL: llvm.return
+end subroutine
+
+! Test 13: Multiple targets in unreachable blocks - all should be deleted
+! ALL-LABEL: llvm.func @_QPtest_multiple_unreachable_blocks
+subroutine test_multiple_unreachable_blocks()
+ real :: v
+ go to 30
+ ! First unreachable block - target should be deleted
+ ! ALL-NOT: {{.*}} = llvm.mlir.constant(1.8{{.*}}e+01 : f32)
+ !$omp target map(tofrom:v)
+ v = 18.0
+ !$omp end target
+ go to 20
+20 continue
+ ! Second unreachable block (only reachable from first unreachable block)
+ ! ALL-NOT: {{.*}} = llvm.mlir.constant(1.9{{.*}}e+01 : f32)
+ !$omp target map(tofrom:v)
+ v = 19.0
+ !$omp end target
+30 continue
+ ! Reachable from entry - target should remain
+ !$omp target map(tofrom:v)
+ ! ALL: omp.target
+ ! ALL: {{.*}} = llvm.mlir.constant(2.0{{.*}}e+01 : f32)
+ v = 20.0
+ !$omp end target
+ ! Expect exactly 1 omp.target in function
+ ! ALL-NOT: omp.target
+ ! ALL: llvm.return
+end subroutine
+
+! Test 14: Both branches reachable - all targets should remain
+! ALL-LABEL: llvm.func @_QPtest_both_branches_reachable
+! ALL: omp.target
+! ALL: omp.target
+! ALL: llvm.return
+subroutine test_both_branches_reachable(cond)
+ logical, intent(in) :: cond
+ real :: v
+ if (cond) then
+ !$omp target map(tofrom:v)
+ v = 21.0
+ !$omp end target
+ else
+ !$omp target map(tofrom:v)
+ v = 22.0
+ !$omp end target
+ end if
+end subroutine
diff --git a/flang/test/Lower/OpenMP/target-dead-code.f90 b/flang/test/Lower/OpenMP/target-dead-code.f90
deleted file mode 100644
index 876618d6d963c..0000000000000
--- a/flang/test/Lower/OpenMP/target-dead-code.f90
+++ /dev/null
@@ -1,88 +0,0 @@
-! RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s --check-prefix=FIR
-
-! Test that OpenMP target regions in dead code are deleted
-
-! Test 1: if (.false.) with target - target should be deleted
-! FIR-LABEL: func.func @_QPtest_dead_simple
-! FIR: %[[FALSE:.*]] = arith.constant false
-! FIR: fir.if %[[FALSE]] {
-! FIR-NOT: omp.target
-subroutine test_dead_simple()
- real :: v
- if (.false.) then
- !$omp target map(tofrom:v)
- v = 1.0
- !$omp end target
- end if
-end subroutine
-
-! Test 2: Live target - should remain
-! FIR-LABEL: func.func @_QPtest_live_simple
-! FIR: omp.target
-subroutine test_live_simple()
- real :: v
- !$omp target map(tofrom:v)
- v = 2.0
- !$omp end target
-end subroutine
-
-! Test 3: Mixed dead and live
-! FIR-LABEL: func.func @_QPtest_mixed
-subroutine test_mixed()
- real :: v
- ! Dead - should be deleted
- ! FIR: fir.if %{{.*}} {
- if (.false.) then
- !$omp target map(tofrom:v)
- v = 3.0
- !$omp end target
- end if
- ! FIR-NOT: omp.target
- ! Live - should remain (expect exactly 1 omp.target in function)
- !$omp target map(tofrom:v)
- ! FIR: omp.target
- v = 4.0
- !$omp end target
-end subroutine
-
-! Test 4: Nested - outer false, target should be deleted
-! FIR-LABEL: func.func @_QPtest_nested_outer_false
-subroutine test_nested_outer_false()
- real :: v
- ! FIR: fir.if %{{.*}} {
- if (.false.) then
- if (.true.) then
- !$omp target map(tofrom:v)
- v = 5.0
- !$omp end target
- end if
- end if
- ! FIR-NOT: omp.target
-end subroutine
-
-! Test 5: Parameter constant - target should be deleted
-! FIR-LABEL: func.func @_QPtest_parameter
-subroutine test_parameter()
- real :: v
- logical, parameter :: DEAD = .false.
- ! FIR: fir.if %{{.*}} {
- if (DEAD) then
- !$omp target map(tofrom:v)
- v = 6.0
- !$omp end target
- end if
- ! FIR-NOT: omp.target
-end subroutine
-
-! FIR-LABEL: func.func @_QPtest_outer
-subroutine test_outer
- implicit none
-contains
- subroutine unused_sub()
- real :: v
- !$omp target map(tofrom: v)
- v = 5.0
- !$omp end target
- end subroutine
- ! FIR-NOT: omp.target
-end subroutine
diff --git a/flang/test/Transforms/OpenMP/delete-unreachable-targets.mlir b/flang/test/Transforms/OpenMP/delete-unreachable-targets.mlir
deleted file mode 100644
index 6db167b51039d..0000000000000
--- a/flang/test/Transforms/OpenMP/delete-unreachable-targets.mlir
+++ /dev/null
@@ -1,322 +0,0 @@
-// RUN: fir-opt --omp-delete-unreachable-targets %s | FileCheck %s
-
-// This test verifies that OpenMP target operations in unreachable code are
-// deleted.
-
-
-// CHECK-LABEL: func.func @test_if_false_simple
-func.func @test_if_false_simple() {
- %false = arith.constant false
- // The target in the dead branch should be removed
- // CHECK: fir.if %false {
- // CHECK-NOT: omp.target
- // CHECK: }
- fir.if %false {
- omp.target kernel_type(generic) {
- omp.terminator
- }
- }
- return
-}
-
-// -----
-
-// CHECK-LABEL: func.func @test_if_true_simple
-func.func @test_if_true_simple() {
- %true = arith.constant true
- // The target should remain since the branch is reachable
- // CHECK: omp.target
- fir.if %true {
- omp.target kernel_type(generic) {
- omp.terminator
- }
- }
- return
-}
-
-// -----
-
-// CHECK-LABEL: func.func @test_nested_outer_false
-func.func @test_nested_outer_false() {
- %false = arith.constant false
- %true = arith.constant true
- // Outer false makes the whole nested structure unreachable
- // CHECK: fir.if %false {
- // CHECK-NOT: omp.target
- // CHECK: }
- fir.if %false {
- fir.if %true {
- omp.target kernel_type(generic) {
- omp.terminator
- }
- }
- }
- return
-}
-
-// -----
-
-// CHECK-LABEL: func.func @test_nested_inner_false
-func.func @test_nested_inner_false() {
- %false = arith.constant false
- %true = arith.constant true
- // Outer true, inner false - target should be removed
- // CHECK: fir.if %true {
- // CHECK: fir.if %false {
- // CHECK-NOT: omp.target
- // CHECK: }
- fir.if %true {
- fir.if %false {
- omp.target kernel_type(generic) {
- omp.terminator
- }
- }
- }
- return
-}
-
-// -----
-
-// CHECK-LABEL: func.func @test_nested_both_true
-func.func @test_nested_both_true() {
- %true1 = arith.constant true
- %true2 = arith.constant true
- // CHECK: omp.target
- fir.if %true1 {
- fir.if %true2 {
- omp.target kernel_type(generic) {
- omp.terminator
- }
- }
- }
- return
-}
-
-// -----
-
-// CHECK-LABEL: func.func @test_mixed_targets
-func.func @test_mixed_targets() {
- %false = arith.constant false
- %true = arith.constant true
-
- // Live target - should remain (expect 2 targets total in output)
- // CHECK: omp.target
- omp.target kernel_type(generic) {
- omp.terminator
- }
-
- // Another live target in if (true) - should remain
- // CHECK: omp.target
- fir.if %true {
- omp.target kernel_type(generic) {
- omp.terminator
- }
- }
-
- // Dead target - will be removed
- // CHECK-NOT: omp.target
- fir.if %false {
- omp.target kernel_type(generic) {
- omp.terminator
- }
- }
-
- return
-}
-
-// -----
-
-// CHECK-LABEL: func.func @test_multiple_dead_targets
-func.func @test_multiple_dead_targets() {
- %false = arith.constant false
-
- // All targets inside dead branch should be removed
- // CHECK-NOT: omp.target
- fir.if %false {
- omp.target kernel_type(generic) {
- omp.terminator
- }
-
- omp.target kernel_type(generic) {
- omp.terminator
- }
-
- omp.target kernel_type(generic) {
- omp.terminator
- }
- }
- return
-}
-
-// -----
-
-// CHECK-LABEL: func.func @test_if_else_false
-func.func @test_if_else_false() {
- %false = arith.constant false
-
- // CHECK: fir.if %false {
- fir.if %false {
- // Then branch is unreachable, target should be deleted
- omp.target kernel_type(generic) {
- omp.terminator
- }
- } else {
- // CHECK-NOT: omp.target
- // CHECK: } else {
- // Else branch is reachable, target should remain
- // CHECK: omp.target
- omp.target kernel_type(generic) {
- omp.terminator
- }
- }
- return
-}
-
-// -----
-
-// CHECK-LABEL: func.func @test_runtime_condition
-func.func @test_runtime_condition(%arg0: i1) {
- // Runtime condition - cannot be optimized, should remain unchanged
- // CHECK: fir.if %arg0 {
- fir.if %arg0 {
- // CHECK: omp.target
- omp.target kernel_type(generic) {
- omp.terminator
- }
- }
- return
-}
-
-// -----
-
-// Test that targets nested in structured control flow within unreachable blocks
-// are correctly identified as unreachable
-// CHECK-LABEL: func.func @test_nested_in_unreachable_block
-func.func @test_nested_in_unreachable_block() {
- cf.br ^bb2
-^bb1:
- // This entire block is unreachable
- // Even though the fir.if condition is true, the whole block is dead
- %true = arith.constant true
- // CHECK: ^bb1:
- // CHECK-NOT: omp.target
- // CHECK: cf.br ^bb2
- fir.if %true {
- omp.target kernel_type(generic) {
- omp.terminator
- }
- }
- cf.br ^bb2
-^bb2:
- // CHECK: ^bb2:
- // CHECK-NEXT: omp.target
- omp.target kernel_type(generic) {
- omp.terminator
- }
- return
-}
-
-// -----
-
-// CHECK-LABEL: func.func @test_unreachable_block_after_branch
-func.func @test_unreachable_block_after_branch() {
- cf.br ^bb2
-^bb1:
- // This block is unreachable - no predecessor branches to it
- // CHECK: ^bb1:
- // CHECK-NOT: omp.target
- // CHECK: cf.br ^bb2
- omp.target kernel_type(generic) {
- omp.terminator
- }
- cf.br ^bb2
-^bb2:
- // This block is reachable
- // CHECK: ^bb2:
- // CHECK-NEXT: omp.target
- omp.target kernel_type(generic) {
- omp.terminator
- }
- return
-}
-
-// -----
-
-// CHECK-LABEL: func.func @test_multiple_unreachable_blocks
-func.func @test_multiple_unreachable_blocks() {
- cf.br ^bb3
-^bb1:
- // Unreachable block - no predecessor branches to it
- // CHECK: ^bb1:
- // CHECK-NOT: omp.target
- // CHECK: cf.br ^bb2
- omp.target kernel_type(generic) {
- omp.terminator
- }
- cf.br ^bb2
-^bb2:
- // Also unreachable - only reachable from ^bb1 which is itself unreachable
- // CHECK: ^bb2:
- // CHECK-NOT: omp.target
- // CHECK: return
- omp.target kernel_type(generic) {
- omp.terminator
- }
- return
-^bb3:
- // Reachable from entry
- // CHECK: ^bb3:
- // CHECK-NEXT: omp.target
- omp.target kernel_type(generic) {
- omp.terminator
- }
- return
-}
-
-// -----
-
-// CHECK-LABEL: func.func @test_both_branches_reachable
-func.func @test_both_branches_reachable(%arg0: i1) {
- cf.cond_br %arg0, ^bb1, ^bb2
-^bb1:
- // CHECK: ^bb1:
- // CHECK-NEXT: omp.target
- omp.target kernel_type(generic) {
- omp.terminator
- }
- cf.br ^bb3
-^bb2:
- // CHECK: ^bb2:
- // CHECK-NEXT: omp.target
- omp.target kernel_type(generic) {
- omp.terminator
- }
- cf.br ^bb3
-^bb3:
- return
-}
-
-// -----
-
-// CHECK-LABEL: func.func @test_disconnected_block
-func.func @test_disconnected_block() {
- // Entry goes directly to exit
- cf.br ^bb2
-^bb1:
- // This block is completely disconnected - no way to reach it
- // CHECK: ^bb1:
- // CHECK-NOT: omp.target
- // CHECK: cf.br ^bb2
- omp.target kernel_type(generic) {
- omp.terminator
- }
- cf.br ^bb2
-^bb2:
- // Reachable from entry
- // CHECK: ^bb2:
- // CHECK-NEXT: omp.target
- omp.target kernel_type(generic) {
- omp.terminator
- }
- return
-}
More information about the flang-commits
mailing list