[flang-commits] [flang] [mlir] [Flang][MLIR][OpenMP] Move function filtering to the omp dialect (PR #214182)
via flang-commits
flang-commits at lists.llvm.org
Wed Aug 5 03:19:56 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
Author: Sergio Afonso (skatrak)
<details>
<summary>Changes</summary>
The `FunctionFilteringPass`, which removes host-only functions when compiling for an OpenMP target device, is currently defined only for Flang. However, it implements logic that would generally be useful for other frontends that can generate OpenMP offloading code. This patch makes that transition by implementing the following changes:
- It rewrites the `FunctionFilteringPass` to work on lower level non-FIR MLIR modules.
- It splits off preexisting logic to check for not-yet-implemented target device features during function filtering to its own pass and it improves context detection to properly diagnostic only device code.
- It delays function filtering to run at the end of the pipeline, as well as the `MarkDeclareTargetPass`. This will enable the latter to run only once in the pipeline after the `UnimplementedDeviceCheckPass` becomes no longer necessary.
One side effect of these changes is that delaying the filtering will cause all following passes to process host functions that are eventually deleted. On the other hand, it minimizes divergence between host and device MLIR modules making passes such as the `DeleteUnreachableTargets` no longer necessary, as well as allowing passes to introduce new host functions without causing problems on the device.
---
Patch is 85.99 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/214182.diff
24 Files Affected:
- (modified) flang/include/flang/Optimizer/OpenMP/Passes.td (+16-10)
- (modified) flang/lib/Optimizer/OpenMP/CMakeLists.txt (+1-1)
- (removed) flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp (-155)
- (added) flang/lib/Optimizer/OpenMP/UnimplementedDeviceCheck.cpp (+98)
- (modified) flang/lib/Optimizer/Passes/Pipelines.cpp (+16-9)
- (modified) flang/test/Fir/basic-program.fir (+4-1)
- (added) flang/test/Integration/OpenMP/function-filtering-2.f90 (+61)
- (added) flang/test/Integration/OpenMP/function-filtering-3.f90 (+51)
- (renamed) flang/test/Integration/OpenMP/function-filtering-4.f90 (+20-13)
- (renamed) flang/test/Integration/OpenMP/function-filtering.f90 (+23-15)
- (modified) flang/test/Lower/OpenMP/declare-target-deferred-marking-reductions.f90 (+4-5)
- (modified) flang/test/Lower/OpenMP/declare-target-deferred-marking.f90 (+6-6)
- (modified) flang/test/Lower/OpenMP/declare-target-implicit-func-and-subr-cap-enter.f90 (+24-24)
- (modified) flang/test/Lower/OpenMP/declare-target-implicit-func-and-subr-cap.f90 (+26-26)
- (modified) flang/test/Lower/OpenMP/declare-target-implicit-tarop-cap.f90 (+11-11)
- (modified) flang/test/Lower/OpenMP/declare-target-named-main-interface.f90 (+5-12)
- (removed) flang/test/Lower/OpenMP/function-filtering-2.f90 (-49)
- (removed) flang/test/Lower/OpenMP/function-filtering-3.f90 (-34)
- (removed) flang/test/Transforms/OpenMP/function-filtering.mlir (-137)
- (modified) flang/test/Transforms/omp-function-filtering-todo.mlir (+67-5)
- (modified) mlir/include/mlir/Dialect/OpenMP/Transforms/Passes.td (+6)
- (modified) mlir/lib/Dialect/OpenMP/Transforms/CMakeLists.txt (+1)
- (added) mlir/lib/Dialect/OpenMP/Transforms/FunctionFiltering.cpp (+109)
- (added) mlir/test/Dialect/OpenMP/function-filter.mlir (+152)
``````````diff
diff --git a/flang/include/flang/Optimizer/OpenMP/Passes.td b/flang/include/flang/Optimizer/OpenMP/Passes.td
index 9ec159e1ba1e0..b81ff842948c3 100644
--- a/flang/include/flang/Optimizer/OpenMP/Passes.td
+++ b/flang/include/flang/Optimizer/OpenMP/Passes.td
@@ -47,16 +47,6 @@ def DeleteUnreachableTargetsPass
let dependentDialects = ["mlir::omp::OpenMPDialect"];
}
-def FunctionFilteringPass : Pass<"omp-function-filtering"> {
- let summary = "Filters out functions intended for the host when compiling "
- "for the target device.";
- let dependentDialects = [
- "mlir::func::FuncDialect",
- "fir::FIROpsDialect",
- "mlir::omp::OpenMPDialect"
- ];
-}
-
def DoConcurrentConversionPass : Pass<"omp-do-concurrent-conversion", "mlir::ModuleOp"> {
let summary = "Map `DO CONCURRENT` loops to OpenMP worksharing loops.";
@@ -139,4 +129,20 @@ def AutomapToTargetDataPass
let dependentDialects = ["mlir::omp::OpenMPDialect"];
}
+def UnimplementedDeviceCheckPass
+ : Pass<"omp-unimplemented-device-check", "::mlir::ModuleOp"> {
+ let summary = "Report not-yet-implemented situations on target device code";
+ let description = [{
+ This pass is for not-yet-implemented cases that neither Flang lowering nor
+ MLIR to LLVM IR translation can properly identify. In particular, it should
+ be used to detect situations that meet all the following:
+ 1. They are supported on the host but not on the device. Then, it cannot
+ be checked during Flang lowering because implicit `declare_target`
+ information hasn't been propagated yet.
+ 2. They need to use FIR operations or types to be reliably detected.
+ Otherwise, `checkImplementationStatus()` in OpenMP MLIR to LLVM IR
+ translation is the preferred location of the check.
+ }];
+}
+
#endif //FORTRAN_OPTIMIZER_OPENMP_PASSES
diff --git a/flang/lib/Optimizer/OpenMP/CMakeLists.txt b/flang/lib/Optimizer/OpenMP/CMakeLists.txt
index db29e93b71dad..9c14716f4f06a 100644
--- a/flang/lib/Optimizer/OpenMP/CMakeLists.txt
+++ b/flang/lib/Optimizer/OpenMP/CMakeLists.txt
@@ -3,7 +3,6 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
add_flang_library(FlangOpenMPTransforms
AutomapToTargetData.cpp
DoConcurrentConversion.cpp
- FunctionFiltering.cpp
GenericLoopConversion.cpp
MapsForPrivatizedSymbols.cpp
MapInfoFinalization.cpp
@@ -12,6 +11,7 @@ add_flang_library(FlangOpenMPTransforms
LowerWorkshare.cpp
LowerNontemporal.cpp
SimdOnly.cpp
+ UnimplementedDeviceCheck.cpp
DEPENDS
FIRDialect
diff --git a/flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp b/flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp
deleted file mode 100644
index ee61dd8881fd0..0000000000000
--- a/flang/lib/Optimizer/OpenMP/FunctionFiltering.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-//===- FunctionFiltering.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 file implements transforms to filter out functions intended for the host
-// when compiling for the device and vice versa.
-//
-//===----------------------------------------------------------------------===//
-
-#include "flang/Optimizer/Builder/Todo.h"
-#include "flang/Optimizer/Dialect/FIRDialect.h"
-#include "flang/Optimizer/Dialect/FIROpsSupport.h"
-#include "flang/Optimizer/OpenMP/Passes.h"
-
-#include "mlir/Dialect/Func/IR/FuncOps.h"
-#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
-#include "mlir/Dialect/OpenMP/OpenMPInterfaces.h"
-#include "llvm/ADT/SmallVector.h"
-
-namespace flangomp {
-#define GEN_PASS_DEF_FUNCTIONFILTERINGPASS
-#include "flang/Optimizer/OpenMP/Passes.h.inc"
-} // namespace flangomp
-
-using namespace mlir;
-
-/// This function triggers TODO errors and halts compilation if it detects
-/// patterns representing unimplemented features.
-///
-/// It exclusively checks situations that cannot be detected after all of the
-/// MLIR pipeline has ran (i.e. at the MLIR to LLVM IR translation stage, where
-/// the preferred location for these types of checks is), and it only checks for
-/// features that have not been implemented for target offload, but are
-/// supported on host execution.
-static void
-checkDeviceImplementationStatus(omp::OffloadModuleInterface offloadModule) {
- if (!offloadModule.getIsGPU())
- return;
-
- offloadModule->walk<WalkOrder::PreOrder>([&](omp::DeclareReductionOp redOp) {
- if (redOp.symbolKnownUseEmpty(offloadModule))
- return WalkResult::advance();
-
- if (!redOp.getByrefElementType())
- return WalkResult::advance();
-
- auto seqTy = dyn_cast<fir::SequenceType>(*redOp.getByrefElementType());
-
- bool isByRefReductionSupported =
- !seqTy || !fir::sequenceWithNonConstantShape(seqTy);
-
- if (!isByRefReductionSupported) {
- TODO(redOp.getLoc(),
- "Reduction of dynamically-shaped arrays are not supported yet "
- "on the GPU.");
- }
-
- return WalkResult::advance();
- });
-}
-
-namespace {
-class FunctionFilteringPass
- : public flangomp::impl::FunctionFilteringPassBase<FunctionFilteringPass> {
-public:
- FunctionFilteringPass() = default;
-
- void runOnOperation() override {
- MLIRContext *context = &getContext();
- OpBuilder opBuilder(context);
- auto op = dyn_cast<omp::OffloadModuleInterface>(getOperation());
- if (!op || !op.getIsTargetDevice())
- return;
-
- op->walk<WalkOrder::PreOrder>([&](func::FuncOp funcOp) {
- // Do not filter functions with target regions inside, because they have
- // to be available for both host and device so that regular and reverse
- // offloading can be supported.
- bool hasTargetRegion =
- funcOp
- ->walk<WalkOrder::PreOrder>([&](omp::TargetOp targetOp) {
- return WalkResult::interrupt();
- })
- .wasInterrupted();
-
- omp::DeclareTargetDeviceType declareType =
- omp::DeclareTargetDeviceType::host;
- auto declareTargetOp =
- dyn_cast<omp::DeclareTargetInterface>(funcOp.getOperation());
- if (declareTargetOp && declareTargetOp.isDeclareTarget())
- declareType = declareTargetOp.getDeclareTargetDeviceType();
-
- // Filtering a function here means deleting it if it doesn't contain a
- // target region. Else we explicitly set the omp.declare_target
- // attribute. The second stage of function filtering at the MLIR to LLVM
- // IR translation level will remove functions that contain the target
- // region from the generated llvm IR.
- if (declareType == omp::DeclareTargetDeviceType::host) {
- SymbolTable::UseRange funcUses = *funcOp.getSymbolUses(op);
- for (SymbolTable::SymbolUse use : funcUses) {
- Operation *callOp = use.getUser();
- if (auto internalFunc = dyn_cast<func::FuncOp>(callOp)) {
- // Do not delete internal procedures holding the symbol of their
- // Fortran host procedure as attribute.
- internalFunc->removeAttr(fir::getHostSymbolAttrName());
- // Set public visibility so that the function is not deleted by MLIR
- // because unused. Changing it is OK here because the function will
- // be deleted anyway in the second filtering phase.
- internalFunc.setVisibility(mlir::SymbolTable::Visibility::Public);
- continue;
- }
- // Prevent dispatch table entries pointing to deleted functions
- // from being removed. This prevents the lowering of any
- // corresponding fir.dispatch ops from triggering errors. These
- // fir.dt_entry ops will point to an undefined symbol as a result,
- // which currently doesn't cause an issue, as fir.dispatch-related ops
- // are later removed by the host op filtering pass.
- if (isa<fir::DTEntryOp>(callOp))
- continue;
-
- // If the callOp has users then replace them with Undef values.
- if (!callOp->use_empty()) {
- SmallVector<Value> undefResults;
- for (Value res : callOp->getResults()) {
- opBuilder.setInsertionPoint(callOp);
- undefResults.emplace_back(
- fir::UndefOp::create(opBuilder, res.getLoc(), res.getType()));
- }
- callOp->replaceAllUsesWith(undefResults);
- }
- // Remove the callOp
- callOp->erase();
- }
-
- if (!hasTargetRegion) {
- funcOp.erase();
- return WalkResult::skip();
- }
-
- if (declareTargetOp)
- declareTargetOp.setDeclareTarget(
- declareType, omp::DeclareTargetCaptureClause::to,
- declareTargetOp.getDeclareTargetAutomap());
- }
- return WalkResult::advance();
- });
-
- checkDeviceImplementationStatus(op);
- }
-};
-} // namespace
diff --git a/flang/lib/Optimizer/OpenMP/UnimplementedDeviceCheck.cpp b/flang/lib/Optimizer/OpenMP/UnimplementedDeviceCheck.cpp
new file mode 100644
index 0000000000000..c393e2f90f88f
--- /dev/null
+++ b/flang/lib/Optimizer/OpenMP/UnimplementedDeviceCheck.cpp
@@ -0,0 +1,98 @@
+//===- UnimplementedDeviceCheck.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Diagnose not-yet-implemented target device cases.
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/OpenMP/Passes.h"
+
+#include "flang/Optimizer/Dialect/FIROpsSupport.h"
+#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+#include "mlir/IR/BuiltinOps.h"
+
+using namespace mlir;
+
+namespace flangomp {
+#define GEN_PASS_DEF_UNIMPLEMENTEDDEVICECHECKPASS
+#include "flang/Optimizer/OpenMP/Passes.h.inc"
+} // namespace flangomp
+
+/// Check whether all uses of the given symbol inside of the module are only
+/// intended for the host.
+static bool allUsesInHostCode(Operation *moduleOp, SymbolOpInterface symOp) {
+ if (auto symUses = symOp.getSymbolUses(moduleOp)) {
+ for (auto symUse : symUses.value()) {
+ Operation *symUser = symUse.getUser();
+ if (!symUser)
+ continue;
+
+ if (symUser->getParentOfType<omp::TargetOp>())
+ return false;
+
+ if (auto declareTargetOp =
+ symUser->getParentOfType<omp::DeclareTargetInterface>()) {
+ if (declareTargetOp.isDeclareTarget() &&
+ declareTargetOp.getDeclareTargetDeviceType() !=
+ omp::DeclareTargetDeviceType::host)
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/// Emit not-yet-implemented errors for reductions over dynamically-shaped
+/// arrays.
+static LogicalResult checkReduction(omp::DeclareReductionOp reductionOp) {
+ if (!reductionOp.getByrefElementType())
+ return success();
+
+ auto seqTy = dyn_cast<fir::SequenceType>(*reductionOp.getByrefElementType());
+
+ bool isByRefReductionSupported =
+ !seqTy || !fir::sequenceWithNonConstantShape(seqTy);
+
+ if (!isByRefReductionSupported)
+ return reductionOp.emitError()
+ << "not yet implemented: Reduction of dynamically-shaped arrays on "
+ "the GPU.";
+
+ return success();
+}
+
+namespace {
+class UnimplementedDeviceCheckPass
+ : public flangomp::impl::UnimplementedDeviceCheckPassBase<
+ UnimplementedDeviceCheckPass> {
+
+ void runOnOperation() override {
+ // Only run checks when compiling for a target device.
+ auto op = dyn_cast<omp::OffloadModuleInterface>(*getOperation());
+ if (!op || !op.getIsTargetDevice())
+ return;
+
+ bool errorsEmitted = false;
+
+ if (op.getIsGPU()) {
+ op->walk([&](omp::DeclareReductionOp reductionOp) {
+ // Only check reductions that aren't exclusively used on the host.
+ if (op.getIsGPU() && !allUsesInHostCode(op, reductionOp)) {
+ if (failed(checkReduction(reductionOp)))
+ errorsEmitted = true;
+ }
+ });
+ }
+
+ if (errorsEmitted)
+ signalPassFailure();
+
+ markAllAnalysesPreserved();
+ }
+};
+} // namespace
diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp
index ba346bfb62111..7781b4593481f 100644
--- a/flang/lib/Optimizer/Passes/Pipelines.cpp
+++ b/flang/lib/Optimizer/Passes/Pipelines.cpp
@@ -365,14 +365,11 @@ void createOpenMPFIRPassPipeline(mlir::PassManager &pm,
pm.addPass(flangomp::createMapsForPrivatizedSymbolsPass());
pm.addPass(flangomp::createAutomapToTargetDataPass());
pm.addPass(flangomp::createMapInfoFinalizationPass());
- pm.addPass(mlir::omp::createMarkDeclareTargetPass());
// Delete unreachable target operations before FunctionFilteringPass
// extracts them.
pm.addPass(flangomp::createDeleteUnreachableTargetsPass());
pm.addPass(flangomp::createGenericLoopConversionPass());
- if (opts.isTargetDevice)
- pm.addPass(flangomp::createFunctionFilteringPass());
}
void createDebugPasses(mlir::PassManager &pm,
@@ -442,18 +439,28 @@ void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
flangomp::createLowerNontemporalPass());
}
+ bool runOMPNonSimdPasses = config.EnableOpenMP && !config.EnableOpenMPSimd;
+ if (runOMPNonSimdPasses) {
+ // Propagate implicit declare target information early in order to diagnose
+ // target device not-yet-implemented cases based on FIR.
+ pm.addPass(mlir::omp::createMarkDeclareTargetPass());
+ pm.addPass(flangomp::createUnimplementedDeviceCheckPass());
+ }
+
fir::addFIRToLLVMPass(pm, config);
pm.addPass(fir::createEmitMIFGlobalCtors());
- if (config.EnableOpenMP && !config.EnableOpenMPSimd) {
+ if (runOMPNonSimdPasses) {
// Since some math operations may be converted to function calls by the
- // ConvertMathToFuncs pass, we need to mark them with the omp.declare_target
- // attribute if they're called from a target region.
+ // ConvertMathToFuncs pass, we need to run the implicit declare_target
+ // propagation and dependent passes late in the pipeline.
pm.addPass(mlir::omp::createMarkDeclareTargetPass());
- // Remove all non target-related operations from host functions still
- // remaining at this point, if compiling for an OpenMP target device. This
- // is required before translating 'omp' dialect operations to LLVM IR.
+ // First remove host-only functions from target device modules, and then
+ // clean up any remaining host functions holding target regions to only
+ // contain the bare minimum host operations needed for target device
+ // compilation.
+ pm.addPass(mlir::omp::createFunctionFilteringPass());
pm.addPass(mlir::omp::createHostOpFilteringPass());
// Convert applicable OpenMP stack allocations to shared memory allocations
diff --git a/flang/test/Fir/basic-program.fir b/flang/test/Fir/basic-program.fir
index 4a483851e7ba6..536963920bdb7 100644
--- a/flang/test/Fir/basic-program.fir
+++ b/flang/test/Fir/basic-program.fir
@@ -183,11 +183,14 @@ func.func @_QQmain() {
// PASSES-NEXT: 'func.func' Pipeline
// PASSES-NEXT: FunctionAttr
// PASSES-NEXT: LowerNontemporalPass
+// PASSES-NEXT: MarkDeclareTargetPass
+// PASSES-NEXT: UnimplementedDeviceCheckPass
// PASSES-NEXT: FIRToLLVMLowering
// PASSES-NEXT: ReconcileUnrealizedCasts
// PASSES-NEXT: EmitMIFGlobalCtors
// PASSES-NEXT: MarkDeclareTargetPass
-// PASSES-NEXT: HostOpFilteringPass
+// PASSES-NEXT: FunctionFilteringPass
+// PASSES-NEXT: HostOpFilteringPass
// PASSES-NEXT: 'llvm.func' Pipeline
// PASSES-NEXT: StackToSharedPass
// PASSES-NEXT: PrepareForOMPOffloadPrivatizationPass
diff --git a/flang/test/Integration/OpenMP/function-filtering-2.f90 b/flang/test/Integration/OpenMP/function-filtering-2.f90
new file mode 100644
index 0000000000000..eda3015811e73
--- /dev/null
+++ b/flang/test/Integration/OpenMP/function-filtering-2.f90
@@ -0,0 +1,61 @@
+!===----------------------------------------------------------------------===!
+! 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 -fopenmp -fopenmp-version=52 -emit-llvm %s -o - | FileCheck --check-prefixes=LLVM-ALL,LLVM-HOST %s
+! RUN: %flang_fc1 -fopenmp -fopenmp-version=52 -emit-hlfir %s -o - | tco -test-gen | FileCheck --check-prefixes=MLIR-ALL,MLIR-HOST %s
+! RUN: %if amdgpu-registered-target %{ %flang_fc1 -triple amdgcn-amd-amdhsa -fopenmp -fopenmp-version=52 -fopenmp-is-target-device -emit-llvm %s -o - | FileCheck --check-prefixes=LLVM-ALL,LLVM-DEVICE %s %}
+! RUN: %if amdgpu-registered-target %{ %flang_fc1 -triple amdgcn-amd-amdhsa -fopenmp -fopenmp-version=52 -fopenmp-is-target-device -emit-hlfir %s -o - | tco -test-gen | FileCheck --check-prefixes=MLIR-ALL,MLIR-DEVICE %s %}
+! RUN: bbc -fopenmp -fopenmp-version=52 -emit-hlfir %s -o - | tco -test-gen | FileCheck --check-prefixes=MLIR-ALL,MLIR-HOST %s
+! RUN: %if amdgpu-registered-target %{ bbc -target amdgcn-amd-amdhsa -fopenmp -fopenmp-version=52 -fopenmp-is-target-device -emit-hlfir %s -o - | tco -test-gen | FileCheck --check-prefixes=MLIR-ALL,MLIR-DEVICE %s %}
+
+! MLIR-ALL: llvm.func @{{.*}}implicit_invocation() attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (to), automap = false>{{.*}}}
+! MLIR-ALL: llvm.return
+! LLVM-ALL: define {{.*}} @{{.*}}implicit_invocation{{.*}}(
+subroutine implicit_invocation()
+end subroutine implicit_invocation
+
+! MLIR-ALL: llvm.func @{{.*}}declaretarget() attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (to), automap = false>{{.*}}}
+! MLIR-ALL: llvm.return
+! LLVM-ALL: define {{.*}} @{{.*}}declaretarget{{.*}}(
+subroutine declaretarget()
+!$omp declare target to(declaretarget) device_type(nohost)
+ call implicit_invocation()
+end subroutine declaretarget
+
+! MLIR-ALL: llvm.func @{{.*}}declaretarget_enter() attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (enter), automap = false>{{.*}}}
+! MLIR-ALL: llvm.return
+! LLVM-ALL: define {{.*}} @{{.*}}declaretarget_enter{{.*}}(
+subroutine declaretarget_enter()
+!$omp declare target enter(declaretarget_enter) device_type(nohost)
+ call implicit_invocation()
+end subroutine declaretarget_enter
+
+! MLIR-ALL: llvm.func @{{.*}}no_declaretarget() attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (to), automap = false>{{.*}}}
+! MLIR-ALL: llvm.return
+! LLVM-ALL: define {{.*}} @{{.*}}no_declaretarget{{.*}}(
+subroutine no_declaretarget()
+end subroutine no_declaretarget
+
+! MLIR-ALL: llvm.func @{{.+}}main(
+! MLIR-ALL: omp.target
+! MLIR-ALL: llvm.return
+
+! MLIR-HOST: llvm.func @main(
+! MLIR-HOST: llvm.return
+! MLIR-DEVICE-NOT: llvm.func @main(
+
+! LLVM-HOST: define {{.*}} @{{.*}}main{{.*}}(
+! LLVM-HOST: {{.*}} @{{.*}}__omp_offloading{{.*}}main_{{.*}}(
+! LLVM-DEVICE-NOT: {{.*}} @{{.*}}main{{.*}}(
+! LLVM-DEVICE: define {{.*}} @{{.*}}__omp_offloading{{.*}}main_{{.*}}(
+program main
+!$omp target
+ call declaretarget()
+ call no_declaretarget()
+!$omp end target
+end program main
diff --git a/flang/test/Integration/OpenMP/function-filtering-3.f90 b/flang/test/Integration/OpenMP/function-filtering-3.f90
new file mode 100644
index 0000000000000..dcc35b1181461
--- /dev/null
+++ b/flang/test/Integration/OpenMP/function-filtering-3.f90
@@ -0,0 +1,51 @@
+!===----------------------------------------------------------------------===!
+! 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
+! con...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/214182
More information about the flang-commits
mailing list