[Flang][OpenMP] Add support for interop construct (#203959)

This adds support for the OpenMP interop construct, which enables
interoperability with foreign runtime environments (e.g., CUDA, HIP).
The init, use, and destroy action clauses are lowered from the Fortran
parse tree to MLIR interop ops and translated to the appropriate runtime
calls. The omp_lib module is extended with interop query API interfaces,
property constants, and return code constants. A semantics fix relaxes
the depend/targetsync constraint for use/destroy directives where the
interop type was established at a separate init site. Unsupported depend
clauses and prefer_type selector-list forms emit explicit diagnostics
instead of being silently dropped.

Assisted-by: Claude Opus 4.6
This commit is contained in:
Sunil Shrestha 2026-07-22 09:03:34 -07:00 committed by GitHub
parent e0ec539108
commit 22351c74e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 1100 additions and 14 deletions

View file

@ -10,6 +10,7 @@
#include "flang/Common/idioms.h"
#include "flang/Evaluate/expression.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Semantics/expression.h"
#include "flang/Semantics/openmp-modifiers.h"
@ -1061,8 +1062,53 @@ Indirect make(const parser::OmpClause::Indirect &inp,
Init make(const parser::OmpClause::Init &inp,
semantics::SemanticsContext &semaCtx) {
// inp -> empty
llvm_unreachable("Empty: init");
// OmpInitClause has modifiers: OmpPreferType, OmpInteropType,
// OmpDepinfoModifier, and an OmpObject (the interop variable).
auto &mods = semantics::OmpGetModifiers(inp.v);
// Extract interop types (repeatable modifier).
Init::InteropTypes interopTypes;
for (auto *interopType :
semantics::OmpGetRepeatableModifier<parser::OmpInteropType>(mods)) {
switch (interopType->v) {
case parser::OmpInteropType::Value::Target:
interopTypes.push_back(Init::InteropType::Target);
break;
case parser::OmpInteropType::Value::Targetsync:
interopTypes.push_back(Init::InteropType::Targetsync);
break;
}
}
// Extract prefer_type (optional modifier).
std::optional<Init::InteropPreference> interopPreference;
if (auto *preferType =
semantics::OmpGetUniqueModifier<parser::OmpPreferType>(mods)) {
Init::InteropPreference prefs;
for (auto &prefSpec : preferType->v) {
common::visit(
common::visitors{
[&](const parser::OmpPreferenceSpecification::
ForeignRuntimeIdentifier &fri) {
prefs.push_back(makeExpr(fri.value(), semaCtx));
},
[&](const std::list<parser::OmpPreferenceSelector> &selectors) {
// TODO: Handle preference-selector lists.
if (!selectors.empty())
TODO_NOLOC("prefer_type with preference-selector lists in "
"interop init clause");
},
},
prefSpec.u);
}
if (!prefs.empty())
interopPreference = std::move(prefs);
}
auto &interopVar = std::get<parser::OmpObject>(inp.v.t);
return Init{{/*InteropPreference=*/std::move(interopPreference),
/*InteropTypes=*/std::move(interopTypes),
/*InteropVar=*/makeObject(interopVar, semaCtx)}};
}
Initializer make(const parser::OmpClause::Initializer &inp,

View file

@ -19,6 +19,7 @@
#include "Utils.h"
#include "flang/Common/idioms.h"
#include "flang/Evaluate/expression.h"
#include "flang/Evaluate/fold.h"
#include "flang/Evaluate/tools.h"
#include "flang/Evaluate/type.h"
#include "flang/Lower/Bridge.h"
@ -56,6 +57,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringSwitch.h"
using namespace Fortran::lower::omp;
using namespace Fortran::common::openmp;
@ -6279,8 +6281,149 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
const parser::OpenMPInteropConstruct &interopConstruct) {
if (!semaCtx.langOptions().OpenMPSimd)
TODO(converter.getCurrentLocation(), "OpenMPInteropConstruct");
if (semaCtx.langOptions().OpenMPSimd)
return;
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
mlir::Location loc = converter.genLocation(interopConstruct.source);
mlir::MLIRContext *context = firOpBuilder.getContext();
List<Clause> clauses = makeClauses(interopConstruct.v.Clauses(), semaCtx);
// Process shared clauses (depend, nowait, device) that apply to all
// action clauses.
lower::StatementContext stmtCtx;
mlir::omp::DependClauseOps dependOps;
mlir::omp::NowaitClauseOps nowaitOps;
mlir::Value deviceValue;
ClauseProcessor cp(converter, semaCtx, clauses);
cp.processDepend(symTable, stmtCtx, dependOps);
cp.processNowait(nowaitOps);
// Process device clause manually.
for (auto &clause : clauses) {
if (auto *deviceClause = std::get_if<clause::Device>(&clause.u)) {
const auto &deviceExpr = std::get<SomeExpr>(deviceClause->t);
deviceValue = fir::getBase(converter.genExprValue(deviceExpr, stmtCtx));
}
}
// Helper to get the address of an interop variable from an Object.
auto getInteropVarAddr = [&](const Object &object) -> mlir::Value {
const semantics::Symbol *sym = object.sym();
assert(sym && "interop variable must have a symbol");
mlir::Value addr = converter.getSymbolAddress(*sym);
assert(addr && "interop variable must have a valid address");
return addr;
};
// Process action clauses: init, destroy, use.
for (auto &clause : clauses) {
if (auto *initClause = std::get_if<clause::Init>(&clause.u)) {
auto &interopVar = std::get<clause::Init::InteropVar>(initClause->t);
auto &interopTypes = std::get<clause::Init::InteropTypes>(initClause->t);
auto &interopPref =
std::get<std::optional<clause::Init::InteropPreference>>(
initClause->t);
mlir::Value interopVarAddr = getInteropVarAddr(interopVar);
// Convert interop types to MLIR attributes. A single init clause may
// list both `target` and `targetsync`; keep them on one op and let the
// LLVM-IR translation collapse them into a single runtime init call,
// matching Clang.
llvm::SmallVector<mlir::Attribute> interopTypeAttrs;
for (auto itype : interopTypes) {
switch (itype) {
case clause::Init::InteropType::Target:
interopTypeAttrs.push_back(mlir::omp::InteropTypeAttr::get(
context, mlir::omp::InteropType::target));
break;
case clause::Init::InteropType::Targetsync:
interopTypeAttrs.push_back(mlir::omp::InteropTypeAttr::get(
context, mlir::omp::InteropType::targetsync));
break;
}
}
auto interopTypesAttr = mlir::ArrayAttr::get(context, interopTypeAttrs);
// Convert prefer_type to I64ArrayAttr if present.
mlir::ArrayAttr preferTypeAttr;
if (interopPref) {
llvm::SmallVector<int64_t> prefValues;
for (auto &pref : *interopPref) {
// Try to evaluate as a constant integer (e.g., omp_ifr_cuda).
if (auto constVal = evaluate::ToInt64(pref)) {
prefValues.push_back(*constVal);
} else if (auto str =
evaluate::GetScalarConstantValue<evaluate::Ascii>(
pref)) {
// Map standard OpenMP foreign-runtime identifier strings to
// their well-known integer values (OpenMP 5.1, Table 22.2).
auto frId = llvm::StringSwitch<std::optional<int64_t>>(
llvm::StringRef(*str).lower())
.Case("cuda", 1)
.Case("cuda_driver", 2)
.Case("opencl", 3)
.Case("sycl", 4)
.Case("hip", 5)
.Case("level_zero", 6)
.Case("hsa", 7)
.Default(std::nullopt);
if (frId)
prefValues.push_back(*frId);
else
TODO(loc, "unknown foreign-runtime identifier in "
"prefer_type");
} else {
TODO(loc, "non-constant prefer_type value in interop init");
}
}
if (!prefValues.empty())
preferTypeAttr = firOpBuilder.getI64ArrayAttr(prefValues);
}
// Emit a single InteropInitOp carrying all interop-types from this init
// clause. The translation to LLVM IR collapses them into one runtime
// call, matching Clang (one init clause -> one __tgt_interop_init).
mlir::omp::InteropInitOp::create(
firOpBuilder, loc, interopVarAddr, interopTypesAttr, preferTypeAttr,
deviceValue,
dependOps.dependKinds.empty()
? nullptr
: firOpBuilder.getArrayAttr(dependOps.dependKinds),
dependOps.dependVars,
/*depend_iterated_kinds=*/nullptr,
/*depend_iterated=*/mlir::ValueRange{}, nowaitOps.nowait);
} else if (auto *destroyClause = std::get_if<clause::Destroy>(&clause.u)) {
assert(destroyClause->v &&
"destroy clause must have an interop variable");
if (destroyClause->v) {
mlir::Value interopVarAddr = getInteropVarAddr(*destroyClause->v);
mlir::omp::InteropDestroyOp::create(
firOpBuilder, loc, interopVarAddr, deviceValue,
dependOps.dependKinds.empty()
? nullptr
: firOpBuilder.getArrayAttr(dependOps.dependKinds),
dependOps.dependVars,
/*depend_iterated_kinds=*/nullptr,
/*depend_iterated=*/mlir::ValueRange{}, nowaitOps.nowait);
}
} else if (auto *useClause = std::get_if<clause::Use>(&clause.u)) {
mlir::Value interopVarAddr = getInteropVarAddr(useClause->v);
mlir::omp::InteropUseOp::create(
firOpBuilder, loc, interopVarAddr, deviceValue,
dependOps.dependKinds.empty()
? nullptr
: firOpBuilder.getArrayAttr(dependOps.dependKinds),
dependOps.dependVars,
/*depend_iterated_kinds=*/nullptr,
/*depend_iterated=*/mlir::ValueRange{}, nowaitOps.nowait);
}
}
}
static void

View file

@ -5975,6 +5975,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::ThreadLimit &x) {
void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
bool isDependClauseOccurred{false};
bool hasInitClause{false};
int targetCount{0}, targetSyncCount{0};
std::set<const Symbol *> objectSymbolList;
const auto &clauseList{std::get<std::optional<parser::OmpClauseList>>(x.v.t)};
@ -5982,6 +5983,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
common::visit(
common::visitors{
[&](const parser::OmpClause::Init &initClause) {
hasInitClause = true;
if (OmpVerifyModifiers(initClause.v, llvm::omp::OMPC_init,
GetContext().directiveSource, context_)) {
@ -6004,6 +6006,38 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
"The '%s' is not allowed on INTEROP construct"_err_en_US,
desc.name.str());
}
// A prefer_type foreign-runtime-identifier must be a
// constant expression of integer OpenMP type or a base
// language string literal. This is enforced for the flat form
// (prefer_type(fr-id, ...)); the OpenMP 6.0
// brace form (prefer_type({fr(...), attr(...)}, ...)) is not
// yet supported in lowering and is diagnosed there, so its
// operands are not validated here.
if (auto *preferType{
OmpGetUniqueModifier<parser::OmpPreferType>(
modifiers)}) {
for (const auto &prefSpec : preferType->v) {
const auto *fri{
std::get_if<parser::OmpPreferenceSpecification::
ForeignRuntimeIdentifier>(&prefSpec.u)};
if (!fri) {
continue;
}
if (const auto *expr{GetExpr(context_, fri->value())}) {
std::optional<evaluate::DynamicType> type{
expr->GetType()};
bool isIntOrChar{type &&
(type->category() ==
evaluate::TypeCategory::Integer ||
type->category() ==
evaluate::TypeCategory::Character)};
if (!evaluate::IsConstantExpr(*expr) || !isIntOrChar) {
context_.Say(fri->value().source,
"The foreign-runtime-identifier in a `prefer_type` modifier must be a constant expression of integer OpenMP type or a base language string literal"_err_en_US);
}
}
}
}
}
const auto *interopVar{parser::Unwrap<parser::OmpObject>(
std::get<parser::OmpObject>(initClause.v.t))};
@ -6058,7 +6092,11 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
context_.Say(GetContext().directiveSource,
"Each interop-type may be specified at most once."_err_en_US);
}
if (isDependClauseOccurred && !targetSyncCount) {
// Only enforce the depend/targetsync constraint when an init clause is
// present on this directive. For use/destroy-only directives, the interop
// object's type was established at its init site, which may be in a
// different statement — we cannot verify it statically here.
if (isDependClauseOccurred && hasInitClause && !targetSyncCount) {
context_.Say(GetContext().directiveSource,
"A DEPEND clause can only appear on the directive if the interop-type includes TARGETSYNC"_err_en_US);
}

View file

@ -1,9 +0,0 @@
! REQUIRES: openmp_runtime
! RUN: %not_todo_cmd %flang_fc1 -emit-llvm %openmp_flags -fopenmp-version=52 -o - %s 2>&1 | FileCheck %s
! CHECK: not yet implemented: OpenMPInteropConstruct
program interop_test
use omp_lib
integer(omp_interop_kind) :: obj
!$omp interop init(targetsync,target: obj)
end program interop_test

View file

@ -0,0 +1,11 @@
! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -fopenmp-version=60 -o - %s 2>&1 | FileCheck %s
! A prefer_type preference-selector list (the OpenMP 6.0 brace form) is valid
! syntax but not yet lowered.
! CHECK: not yet implemented: prefer_type with preference-selector lists in interop init clause
subroutine interop_prefer_type_selector_list(obj)
integer(8) :: obj
!$omp interop init(prefer_type({fr("cuda")}), target: obj)
end subroutine

View file

@ -0,0 +1,11 @@
! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -fopenmp-version=60 -o - %s 2>&1 | FileCheck %s
! A prefer_type foreign-runtime identifier string that is not one of the
! standard OpenMP names cannot be mapped to a runtime id.
! CHECK: not yet implemented: unknown foreign-runtime identifier in prefer_type
subroutine interop_prefer_type_unknown_fr(obj)
integer(8) :: obj
!$omp interop init(prefer_type("no_such_runtime"), target: obj)
end subroutine

View file

@ -0,0 +1,175 @@
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=60 %s -o - | FileCheck %s
!===============================================================================
! Interop Init — target
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_init(
!CHECK-SAME: %[[ARG:.*]]: !fir.ref<i64> {fir.bindc_name = "obj"})
!CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ARG]]
!CHECK: omp.interop.init %[[DECL]]#0 : !fir.ref<i64> interop_types([#omp<interop_type(target)>])
subroutine test_interop_init(obj)
integer(8) :: obj
!$omp interop init(target: obj)
end subroutine
!===============================================================================
! Interop Init — targetsync
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_init_targetsync(
!CHECK: omp.interop.init %{{.*}} : !fir.ref<i64> interop_types([#omp<interop_type(targetsync)>])
subroutine test_interop_init_targetsync(obj)
integer(8) :: obj
!$omp interop init(targetsync: obj)
end subroutine
!===============================================================================
! Interop Init — targetsync, target (both)
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_init_both(
!CHECK: omp.interop.init %{{.*}} : !fir.ref<i64> interop_types([#omp<interop_type(targetsync)>, #omp<interop_type(target)>])
subroutine test_interop_init_both(obj)
integer(8) :: obj
!$omp interop init(targetsync, target: obj)
end subroutine
!===============================================================================
! Interop Init — untyped (OpenMP 6.0: interop-type modifier is optional)
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_init_untyped(
!CHECK: omp.interop.init %{{.*}} : !fir.ref<i64> interop_types([])
subroutine test_interop_init_untyped(obj)
integer(8) :: obj
!$omp interop init(obj)
end subroutine
!===============================================================================
! Interop Init — nowait
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_init_nowait(
!CHECK: omp.interop.init %{{.*}} : !fir.ref<i64> interop_types([#omp<interop_type(target)>]) nowait
subroutine test_interop_init_nowait(obj)
integer(8) :: obj
!$omp interop init(target: obj) nowait
end subroutine
!===============================================================================
! Interop Init — device clause
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_device(
!CHECK: %[[DEV:.*]] = fir.load %{{.*}} : !fir.ref<i32>
!CHECK: omp.interop.init %{{.*}} : !fir.ref<i64> interop_types([#omp<interop_type(target)>]) device(%[[DEV]] : i32)
subroutine test_interop_device(obj, dev)
integer(8) :: obj
integer :: dev
!$omp interop device(dev) init(target: obj)
end subroutine
!===============================================================================
! Interop Init — prefer_type with string FR identifiers
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_prefer_str(
!CHECK: omp.interop.init %{{.*}} : !fir.ref<i64> interop_types([#omp<interop_type(targetsync)>]) prefer_type([1, 6])
subroutine test_interop_prefer_str(obj)
integer(8) :: obj
!$omp interop init(prefer_type("cuda", "level_zero"), targetsync: obj)
end subroutine
!===============================================================================
! Interop Init — prefer_type with string FR identifier (hip)
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_prefer_hip(
!CHECK: omp.interop.init %{{.*}} : !fir.ref<i64> interop_types([#omp<interop_type(target)>]) prefer_type([5])
subroutine test_interop_prefer_hip(obj)
integer(8) :: obj
!$omp interop init(prefer_type("hip"), target: obj)
end subroutine
!===============================================================================
! Interop Init — prefer_type with integer constant FR identifiers
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_prefer_int(
!CHECK: omp.interop.init %{{.*}} : !fir.ref<i64> interop_types([#omp<interop_type(targetsync)>]) prefer_type([4])
subroutine test_interop_prefer_int(obj)
integer(8) :: obj
integer, parameter :: omp_ifr_sycl = 4
!$omp interop init(prefer_type(omp_ifr_sycl), targetsync: obj)
end subroutine
!===============================================================================
! Interop Use
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_use(
!CHECK: omp.interop.use %{{.*}} : !fir.ref<i64>
subroutine test_interop_use(obj)
integer(8) :: obj
!$omp interop use(obj)
end subroutine
!===============================================================================
! Interop Use — nowait
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_use_nowait(
!CHECK: omp.interop.use %{{.*}} : !fir.ref<i64> nowait
subroutine test_interop_use_nowait(obj)
integer(8) :: obj
!$omp interop use(obj) nowait
end subroutine
!===============================================================================
! Interop Use — device clause
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_use_device(
!CHECK: %[[DEV:.*]] = fir.load %{{.*}} : !fir.ref<i32>
!CHECK: omp.interop.use %{{.*}} : !fir.ref<i64> device(%[[DEV]] : i32)
subroutine test_interop_use_device(obj, dev)
integer(8) :: obj
integer :: dev
!$omp interop use(obj) device(dev)
end subroutine
!===============================================================================
! Interop Destroy
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_destroy(
!CHECK: omp.interop.destroy %{{.*}} : !fir.ref<i64>
subroutine test_interop_destroy(obj)
integer(8) :: obj
!$omp interop destroy(obj)
end subroutine
!===============================================================================
! Interop Destroy — nowait
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_destroy_nowait(
!CHECK: omp.interop.destroy %{{.*}} : !fir.ref<i64> nowait
subroutine test_interop_destroy_nowait(obj)
integer(8) :: obj
!$omp interop destroy(obj) nowait
end subroutine
!===============================================================================
! Interop Destroy — device clause
!===============================================================================
!CHECK-LABEL: func.func @_QPtest_interop_destroy_device(
!CHECK: %[[DEV:.*]] = fir.load %{{.*}} : !fir.ref<i32>
!CHECK: omp.interop.destroy %{{.*}} : !fir.ref<i64> device(%[[DEV]] : i32)
subroutine test_interop_destroy_device(obj, dev)
integer(8) :: obj
integer :: dev
!$omp interop destroy(obj) device(dev)
end subroutine

View file

@ -0,0 +1,24 @@
! REQUIRES: openmp_runtime
! RUN: %python %S/../test_errors.py %s %flang %openmp_flags -fopenmp-version=60
! OpenMP Version 6.0
! 14.1 Interop construct
! In OpenMP 6.0 the interop-type modifier on an INIT clause is optional, so
! INIT(obj) alone is accepted. A DEPEND clause, however, requires the
! interop-type to include TARGETSYNC, which an untyped INIT does not provide,
! so INIT(obj) combined with DEPEND is diagnosed.
SUBROUTINE test_interop_untyped()
USE omp_lib
INTEGER(OMP_INTEROP_KIND) :: obj
!$OMP INTEROP INIT(obj)
PRINT *, 'pass'
END SUBROUTINE test_interop_untyped
SUBROUTINE test_interop_untyped_depend()
USE omp_lib
INTEGER(OMP_INTEROP_KIND) :: obj
!ERROR: A DEPEND clause can only appear on the directive if the interop-type includes TARGETSYNC
!$OMP INTEROP INIT(obj) DEPEND(INOUT: obj)
PRINT *, 'pass'
END SUBROUTINE test_interop_untyped_depend

View file

@ -0,0 +1,30 @@
! REQUIRES: openmp_runtime
! RUN: %python %S/../test_errors.py %s %flang %openmp_flags -fopenmp-version=60
! OpenMP Version 6.0
! 14.1 Interop construct
! The foreign-runtime-identifier in a `prefer_type` modifier must be a constant
! expression of integer OpenMP type or a base language string literal.
SUBROUTINE test_prefer_type_nonconstant()
USE omp_lib
INTEGER(OMP_INTEROP_KIND) :: obj
INTEGER :: n
!ERROR: The foreign-runtime-identifier in a `prefer_type` modifier must be a constant expression of integer OpenMP type or a base language string literal
!$OMP INTEROP INIT(PREFER_TYPE(n), TARGET: obj)
PRINT *, 'pass'
END SUBROUTINE test_prefer_type_nonconstant
SUBROUTINE test_prefer_type_constant_int()
USE omp_lib
INTEGER(OMP_INTEROP_KIND) :: obj
!$OMP INTEROP INIT(PREFER_TYPE(omp_ifr_cuda), TARGET: obj)
PRINT *, 'pass'
END SUBROUTINE test_prefer_type_constant_int
SUBROUTINE test_prefer_type_string()
USE omp_lib
INTEGER(OMP_INTEROP_KIND) :: obj
!$OMP INTEROP INIT(PREFER_TYPE("cuda"), TARGET: obj)
PRINT *, 'pass'
END SUBROUTINE test_prefer_type_string

View file

@ -8227,6 +8227,8 @@ CallInst *OpenMPIRBuilder::createOMPInteropInit(
Value *ThreadId = getOrCreateThreadID(Ident);
if (Device == nullptr)
Device = Constant::getAllOnesValue(Int32);
else if (Device->getType() != Int32)
Device = Builder.CreateIntCast(Device, Int32, /*isSigned=*/true);
Constant *InteropTypeVal = ConstantInt::get(Int32, (int)InteropType);
if (NumDependences == nullptr) {
NumDependences = ConstantInt::get(Int32, 0);
@ -8255,6 +8257,8 @@ CallInst *OpenMPIRBuilder::createOMPInteropDestroy(
Value *ThreadId = getOrCreateThreadID(Ident);
if (Device == nullptr)
Device = Constant::getAllOnesValue(Int32);
else if (Device->getType() != Int32)
Device = Builder.CreateIntCast(Device, Int32, /*isSigned=*/true);
if (NumDependences == nullptr) {
NumDependences = ConstantInt::get(Int32, 0);
PointerType *PointerTypeVar = PointerType::getUnqual(M.getContext());
@ -8283,6 +8287,8 @@ CallInst *OpenMPIRBuilder::createOMPInteropUse(const LocationDescription &Loc,
Value *ThreadId = getOrCreateThreadID(Ident);
if (Device == nullptr)
Device = Constant::getAllOnesValue(Int32);
else if (Device->getType() != Int32)
Device = Builder.CreateIntCast(Device, Int32, /*isSigned=*/true);
if (NumDependences == nullptr) {
NumDependences = ConstantInt::get(Int32, 0);
PointerType *PointerTypeVar = PointerType::getUnqual(M.getContext());

View file

@ -79,6 +79,16 @@ def TaskDependArrayAttr
let constBuilderCall = ?;
}
//===----------------------------------------------------------------------===//
// InteropTypeArrayAttr
//===----------------------------------------------------------------------===//
def InteropTypeArrayAttr
: TypedArrayAttrBase<InteropTypeAttr,
InteropTypeAttr.summary # " array"> {
let constBuilderCall = ?;
}
//===----------------------------------------------------------------------===//
// VersionAttr
//===----------------------------------------------------------------------===//

View file

@ -377,4 +377,22 @@ def FallbackModifierAttr : OpenMP_EnumAttr<FallbackModifier,
let assemblyFormat = "`(` $value `)`";
}
//===----------------------------------------------------------------------===//
// interop_type for interop construct
//===----------------------------------------------------------------------===//
def InteropTypeTarget : I32EnumAttrCase<"target", 0>;
def InteropTypeTargetSync : I32EnumAttrCase<"targetsync", 1>;
def InteropType : OpenMP_I32EnumAttr<
"InteropType",
"interop type", [
InteropTypeTarget,
InteropTypeTargetSync
]>;
def InteropTypeAttr : OpenMP_EnumAttr<InteropType, "interop_type"> {
let assemblyFormat = "`(` $value `)`";
}
#endif // OPENMP_ENUMS

View file

@ -2655,4 +2655,104 @@ def GroupprivateOp : OpenMP_Op<"groupprivate",
}];
}
//===----------------------------------------------------------------------===//
// 14.1 interop construct
//===----------------------------------------------------------------------===//
def InteropInitOp
: OpenMP_Op<"interop.init", traits = [AttrSizedOperandSegments],
clauses = [OpenMP_DependClause, OpenMP_NowaitClause]> {
let summary = "interop init operation";
let description = [{
The interop init operation initializes an interop object for
foreign runtime interoperability. The `interop_type` attribute specifies
whether the interop object provides access to the target execution
environment (`target`), a synchronization object (`targetsync`), or both.
The optional `prefer_type` attribute provides a list of preferred foreign
runtime types as integer identifiers.
The optional `device` operand specifies the device number.
}] # clausesDescription;
let arguments = !con((ins
OpenMP_PointerLikeType:$interop_var,
InteropTypeArrayAttr:$interop_types,
OptionalAttr<I64ArrayAttr>:$prefer_type,
Optional<AnyInteger>:$device),
clausesArgs);
let assemblyFormat = [{
$interop_var `:` type($interop_var)
`interop_types` `(` $interop_types `)`
(`prefer_type` `(` $prefer_type^ `)`)?
(`device` `(` $device^ `:` type($device) `)`)?
oilist(
`depend` `(`
custom<DependVarList>($depend_vars, type($depend_vars), $depend_kinds,
$depend_iterated, type($depend_iterated),
$depend_iterated_kinds) `)`
| `nowait` $nowait
)
attr-dict
}];
}
def InteropUseOp
: OpenMP_Op<"interop.use", traits = [AttrSizedOperandSegments],
clauses = [OpenMP_DependClause, OpenMP_NowaitClause]> {
let summary = "interop use operation";
let description = [{
The interop use operation indicates use of an interop object. This is
used in combination with depend clauses to synchronize tasks with
foreign runtime operations.
}] # clausesDescription;
let arguments = !con((ins
OpenMP_PointerLikeType:$interop_var,
Optional<AnyInteger>:$device),
clausesArgs);
let assemblyFormat = [{
$interop_var `:` type($interop_var)
(`device` `(` $device^ `:` type($device) `)`)?
oilist(
`depend` `(`
custom<DependVarList>($depend_vars, type($depend_vars), $depend_kinds,
$depend_iterated, type($depend_iterated),
$depend_iterated_kinds) `)`
| `nowait` $nowait
)
attr-dict
}];
}
def InteropDestroyOp
: OpenMP_Op<"interop.destroy", traits = [AttrSizedOperandSegments],
clauses = [OpenMP_DependClause, OpenMP_NowaitClause]> {
let summary = "interop destroy operation";
let description = [{
The interop destroy operation releases an interop object and frees
any resources associated with it.
}] # clausesDescription;
let arguments = !con((ins
OpenMP_PointerLikeType:$interop_var,
Optional<AnyInteger>:$device),
clausesArgs);
let assemblyFormat = [{
$interop_var `:` type($interop_var)
(`device` `(` $device^ `:` type($device) `)`)?
oilist(
`depend` `(`
custom<DependVarList>($depend_vars, type($depend_vars), $depend_kinds,
$depend_iterated, type($depend_iterated),
$depend_iterated_kinds) `)`
| `nowait` $nowait
)
attr-dict
}];
}
#endif // OPENMP_OPS

View file

@ -4364,6 +4364,104 @@ convertOmpTaskgroupOp(omp::TaskgroupOp tgOp, llvm::IRBuilderBase &builder,
return success();
}
static LogicalResult
convertOmpInteropInitOp(omp::InteropInitOp initOp, llvm::IRBuilderBase &builder,
LLVM::ModuleTranslation &moduleTranslation) {
if (!initOp.getDependVars().empty() || initOp.getDependKinds() ||
!initOp.getDependIterated().empty() || initOp.getDependIteratedKinds())
return initOp.emitError()
<< "not yet implemented: Unhandled clause depend in "
<< omp::InteropInitOp::getOperationName() << " operation";
llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
llvm::Value *interopVar =
moduleTranslation.lookupValue(initOp.getInteropVar());
llvm::Value *device = initOp.getDevice()
? moduleTranslation.lookupValue(initOp.getDevice())
: nullptr;
// TODO: Handle depend clauses when supported.
llvm::Value *numDeps = llvm::ConstantInt::get(builder.getInt32Ty(), 0);
llvm::Value *depArray = llvm::ConstantPointerNull::get(builder.getPtrTy());
bool hasNowait = initOp.getNowait();
// A single `init` clause may list both `target` and `targetsync`, but the
// runtime init call takes a single interop-type. Collapse the set to one
// value, matching Clang: if `target` is present use Target, otherwise
// TargetSync. The offload runtime object model supports only one type per
// object; representing both would require a runtime change.
bool hasTarget = false, hasTargetSync = false;
for (mlir::Attribute typeAttr : initOp.getInteropTypes()) {
switch (cast<omp::InteropTypeAttr>(typeAttr).getValue()) {
case omp::InteropType::target:
hasTarget = true;
break;
case omp::InteropType::targetsync:
hasTargetSync = true;
break;
}
}
llvm::omp::OMPInteropType interopType =
(!hasTarget && hasTargetSync) ? llvm::omp::OMPInteropType::TargetSync
: llvm::omp::OMPInteropType::Target;
ompBuilder->createOMPInteropInit(builder, interopVar, interopType, device,
numDeps, depArray, hasNowait);
return success();
}
static LogicalResult
convertOmpInteropDestroyOp(omp::InteropDestroyOp destroyOp,
llvm::IRBuilderBase &builder,
LLVM::ModuleTranslation &moduleTranslation) {
if (!destroyOp.getDependVars().empty() || destroyOp.getDependKinds() ||
!destroyOp.getDependIterated().empty() ||
destroyOp.getDependIteratedKinds())
return destroyOp.emitError()
<< "not yet implemented: Unhandled clause depend in "
<< omp::InteropDestroyOp::getOperationName() << " operation";
llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
llvm::Value *interopVar =
moduleTranslation.lookupValue(destroyOp.getInteropVar());
llvm::Value *device =
destroyOp.getDevice()
? moduleTranslation.lookupValue(destroyOp.getDevice())
: nullptr;
llvm::Value *numDeps = llvm::ConstantInt::get(builder.getInt32Ty(), 0);
llvm::Value *depArray = llvm::ConstantPointerNull::get(builder.getPtrTy());
bool hasNowait = destroyOp.getNowait();
ompBuilder->createOMPInteropDestroy(builder, interopVar, device, numDeps,
depArray, hasNowait);
return success();
}
static LogicalResult
convertOmpInteropUseOp(omp::InteropUseOp useOp, llvm::IRBuilderBase &builder,
LLVM::ModuleTranslation &moduleTranslation) {
if (!useOp.getDependVars().empty() || useOp.getDependKinds() ||
!useOp.getDependIterated().empty() || useOp.getDependIteratedKinds())
return useOp.emitError()
<< "not yet implemented: Unhandled clause depend in "
<< omp::InteropUseOp::getOperationName() << " operation";
llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
llvm::Value *interopVar =
moduleTranslation.lookupValue(useOp.getInteropVar());
llvm::Value *device = useOp.getDevice()
? moduleTranslation.lookupValue(useOp.getDevice())
: nullptr;
llvm::Value *numDeps = llvm::ConstantInt::get(builder.getInt32Ty(), 0);
llvm::Value *depArray = llvm::ConstantPointerNull::get(builder.getPtrTy());
bool hasNowait = useOp.getNowait();
ompBuilder->createOMPInteropUse(builder, interopVar, device, numDeps,
depArray, hasNowait);
return success();
}
static LogicalResult
convertOmpTaskwaitOp(omp::TaskwaitOp twOp, llvm::IRBuilderBase &builder,
LLVM::ModuleTranslation &moduleTranslation) {
@ -9802,6 +9900,15 @@ LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation(
.Case([&](omp::TaskwaitOp op) {
return convertOmpTaskwaitOp(op, builder, moduleTranslation);
})
.Case([&](omp::InteropInitOp op) {
return convertOmpInteropInitOp(op, builder, moduleTranslation);
})
.Case([&](omp::InteropDestroyOp op) {
return convertOmpInteropDestroyOp(op, builder, moduleTranslation);
})
.Case([&](omp::InteropUseOp op) {
return convertOmpInteropUseOp(op, builder, moduleTranslation);
})
.Case<omp::YieldOp, omp::TerminatorOp, omp::DeclareMapperOp,
omp::DeclareMapperInfoOp, omp::DeclareReductionOp,
omp::CriticalDeclareOp>([](auto op) {

View file

@ -4234,3 +4234,57 @@ func.func @omp_target_map_iterated(%lb : index, %ub : index, %step : index,
}
return
}
// -----
// CHECK-LABEL: func.func @omp_interop_init
func.func @omp_interop_init(%obj : !llvm.ptr, %device : i32) -> () {
// CHECK: omp.interop.init %{{.*}} : !llvm.ptr interop_types([#omp<interop_type(target)>])
omp.interop.init %obj : !llvm.ptr interop_types([#omp<interop_type(target)>])
// CHECK: omp.interop.init %{{.*}} : !llvm.ptr interop_types([#omp<interop_type(targetsync)>])
omp.interop.init %obj : !llvm.ptr interop_types([#omp<interop_type(targetsync)>])
// CHECK: omp.interop.init %{{.*}} : !llvm.ptr interop_types([#omp<interop_type(targetsync)>, #omp<interop_type(target)>]) prefer_type([1, 6]) device(%{{.*}} : i32) nowait
omp.interop.init %obj : !llvm.ptr interop_types([#omp<interop_type(targetsync)>, #omp<interop_type(target)>]) prefer_type([1, 6]) device(%device : i32) nowait
return
}
// -----
// CHECK-LABEL: func.func @omp_interop_use
func.func @omp_interop_use(%obj : !llvm.ptr, %device : i32) -> () {
// CHECK: omp.interop.use %{{.*}} : !llvm.ptr
omp.interop.use %obj : !llvm.ptr
// CHECK: omp.interop.use %{{.*}} : !llvm.ptr device(%{{.*}} : i32) nowait
omp.interop.use %obj : !llvm.ptr device(%device : i32) nowait
return
}
// -----
// CHECK-LABEL: func.func @omp_interop_destroy
func.func @omp_interop_destroy(%obj : !llvm.ptr, %device : i32) -> () {
// CHECK: omp.interop.destroy %{{.*}} : !llvm.ptr
omp.interop.destroy %obj : !llvm.ptr
// CHECK: omp.interop.destroy %{{.*}} : !llvm.ptr device(%{{.*}} : i32) nowait
omp.interop.destroy %obj : !llvm.ptr device(%device : i32) nowait
return
}
// -----
// CHECK-LABEL: func.func @omp_interop_depend
func.func @omp_interop_depend(%obj : !llvm.ptr, %dep : !llvm.ptr) -> () {
// CHECK: omp.interop.init %{{.*}} : !llvm.ptr interop_types([#omp<interop_type(targetsync)>]) depend(taskdependinout -> %{{.*}} : !llvm.ptr)
omp.interop.init %obj : !llvm.ptr interop_types([#omp<interop_type(targetsync)>]) depend(taskdependinout -> %dep : !llvm.ptr)
// CHECK: omp.interop.use %{{.*}} : !llvm.ptr depend(taskdependin -> %{{.*}} : !llvm.ptr)
omp.interop.use %obj : !llvm.ptr depend(taskdependin -> %dep : !llvm.ptr)
// CHECK: omp.interop.destroy %{{.*}} : !llvm.ptr depend(taskdependout -> %{{.*}} : !llvm.ptr)
omp.interop.destroy %obj : !llvm.ptr depend(taskdependout -> %dep : !llvm.ptr)
return
}

View file

@ -0,0 +1,28 @@
// RUN: rm -rf %t && split-file %s %t
// RUN: not mlir-translate --mlir-to-llvmir %t/init.mlir 2>&1 | FileCheck %s --check-prefix=INIT
// RUN: not mlir-translate --mlir-to-llvmir %t/use.mlir 2>&1 | FileCheck %s --check-prefix=USE
// RUN: not mlir-translate --mlir-to-llvmir %t/destroy.mlir 2>&1 | FileCheck %s --check-prefix=DESTROY
// The depend clause on interop operations is not yet handled by the
// translation to LLVM IR; each action op must emit a clean diagnostic.
//--- init.mlir
// INIT: error: not yet implemented: Unhandled clause depend in omp.interop.init operation
llvm.func @test_interop_init_depend(%interop: !llvm.ptr, %dep: !llvm.ptr) {
omp.interop.init %interop : !llvm.ptr interop_types([#omp<interop_type(targetsync)>]) depend(taskdependinout -> %dep : !llvm.ptr)
llvm.return
}
//--- use.mlir
// USE: error: not yet implemented: Unhandled clause depend in omp.interop.use operation
llvm.func @test_interop_use_depend(%interop: !llvm.ptr, %dep: !llvm.ptr) {
omp.interop.use %interop : !llvm.ptr depend(taskdependinout -> %dep : !llvm.ptr)
llvm.return
}
//--- destroy.mlir
// DESTROY: error: not yet implemented: Unhandled clause depend in omp.interop.destroy operation
llvm.func @test_interop_destroy_depend(%interop: !llvm.ptr, %dep: !llvm.ptr) {
omp.interop.destroy %interop : !llvm.ptr depend(taskdependinout -> %dep : !llvm.ptr)
llvm.return
}

View file

@ -0,0 +1,95 @@
// RUN: mlir-translate --mlir-to-llvmir %s | FileCheck %s
// CHECK-LABEL: define void @test_interop_init(
// CHECK-SAME: ptr %[[OBJ:.*]])
// CHECK: %[[GTID:.*]] = call i32 @__kmpc_global_thread_num(ptr @{{.*}})
// CHECK: call void @__tgt_interop_init(ptr @{{.*}}, i32 %[[GTID]], ptr %[[OBJ]], i32 1, i32 -1, i32 0, ptr null, i32 0)
// CHECK: ret void
llvm.func @test_interop_init(%arg0: !llvm.ptr) {
%0 = llvm.mlir.constant(1 : i64) : i64
omp.interop.init %arg0 : !llvm.ptr interop_types([#omp<interop_type(target)>])
llvm.return
}
// CHECK-LABEL: define void @test_interop_init_targetsync(
// CHECK: call void @__tgt_interop_init(ptr @{{.*}}, i32 %{{.*}}, ptr %{{.*}}, i32 2, i32 -1, i32 0, ptr null, i32 0)
llvm.func @test_interop_init_targetsync(%arg0: !llvm.ptr) {
omp.interop.init %arg0 : !llvm.ptr interop_types([#omp<interop_type(targetsync)>])
llvm.return
}
// CHECK-LABEL: define void @test_interop_init_both(
// CHECK: call void @__tgt_interop_init(ptr @{{.*}}, i32 %{{.*}}, ptr %{{.*}}, i32 1, i32 -1, i32 0, ptr null, i32 0)
// CHECK-NOT: call void @__tgt_interop_init
llvm.func @test_interop_init_both(%arg0: !llvm.ptr) {
omp.interop.init %arg0 : !llvm.ptr interop_types([#omp<interop_type(targetsync)>, #omp<interop_type(target)>])
llvm.return
}
// CHECK-LABEL: define void @test_interop_use(
// CHECK: %[[GTID:.*]] = call i32 @__kmpc_global_thread_num(ptr @{{.*}})
// CHECK: call void @__tgt_interop_use(ptr @{{.*}}, i32 %[[GTID]], ptr %{{.*}}, i32 -1, i32 0, ptr null, i32 0)
// CHECK: ret void
llvm.func @test_interop_use(%arg0: !llvm.ptr) {
omp.interop.use %arg0 : !llvm.ptr
llvm.return
}
// CHECK-LABEL: define void @test_interop_destroy(
// CHECK: %[[GTID:.*]] = call i32 @__kmpc_global_thread_num(ptr @{{.*}})
// CHECK: call void @__tgt_interop_destroy(ptr @{{.*}}, i32 %[[GTID]], ptr %{{.*}}, i32 -1, i32 0, ptr null, i32 0)
// CHECK: ret void
llvm.func @test_interop_destroy(%arg0: !llvm.ptr) {
omp.interop.destroy %arg0 : !llvm.ptr
llvm.return
}
// CHECK-LABEL: define void @test_interop_init_nowait(
// CHECK: call void @__tgt_interop_init(ptr @{{.*}}, i32 %{{.*}}, ptr %{{.*}}, i32 1, i32 -1, i32 0, ptr null, i32 1)
llvm.func @test_interop_init_nowait(%arg0: !llvm.ptr) {
omp.interop.init %arg0 : !llvm.ptr interop_types([#omp<interop_type(target)>]) nowait
llvm.return
}
// CHECK-LABEL: define void @test_interop_destroy_nowait(
// CHECK: call void @__tgt_interop_destroy(ptr @{{.*}}, i32 %{{.*}}, ptr %{{.*}}, i32 -1, i32 0, ptr null, i32 1)
llvm.func @test_interop_destroy_nowait(%arg0: !llvm.ptr) {
omp.interop.destroy %arg0 : !llvm.ptr nowait
llvm.return
}
// CHECK-LABEL: define void @test_interop_init_device(
// CHECK: call void @__tgt_interop_init(ptr @{{.*}}, i32 %{{.*}}, ptr %{{.*}}, i32 1, i32 %{{.*}}, i32 0, ptr null, i32 0)
llvm.func @test_interop_init_device(%arg0: !llvm.ptr, %arg1: i32) {
omp.interop.init %arg0 : !llvm.ptr interop_types([#omp<interop_type(target)>]) device(%arg1 : i32)
llvm.return
}
// CHECK-LABEL: define void @test_interop_init_device_i64(
// CHECK: %[[DEVICE:.*]] = trunc i64 %{{.*}} to i32
// CHECK: call void @__tgt_interop_init(ptr @{{.*}}, i32 %{{.*}}, ptr %{{.*}}, i32 1, i32 %[[DEVICE]], i32 0, ptr null, i32 0)
llvm.func @test_interop_init_device_i64(%arg0: !llvm.ptr, %arg1: i64) {
omp.interop.init %arg0 : !llvm.ptr interop_types([#omp<interop_type(target)>]) device(%arg1 : i64)
llvm.return
}
// CHECK-LABEL: define void @test_interop_destroy_device_i64(
// CHECK: %[[DEVICE:.*]] = trunc i64 %{{.*}} to i32
// CHECK: call void @__tgt_interop_destroy(ptr @{{.*}}, i32 %{{.*}}, ptr %{{.*}}, i32 %[[DEVICE]], i32 0, ptr null, i32 0)
llvm.func @test_interop_destroy_device_i64(%arg0: !llvm.ptr, %arg1: i64) {
omp.interop.destroy %arg0 : !llvm.ptr device(%arg1 : i64)
llvm.return
}
// CHECK-LABEL: define void @test_interop_use_device_i64(
// CHECK: %[[DEVICE:.*]] = trunc i64 %{{.*}} to i32
// CHECK: call void @__tgt_interop_use(ptr @{{.*}}, i32 %{{.*}}, ptr %{{.*}}, i32 %[[DEVICE]], i32 0, ptr null, i32 0)
llvm.func @test_interop_use_device_i64(%arg0: !llvm.ptr, %arg1: i64) {
omp.interop.use %arg0 : !llvm.ptr device(%arg1 : i64)
llvm.return
}
// CHECK: declare i32 @__kmpc_global_thread_num(ptr)
// CHECK: declare void @__tgt_interop_init(ptr, i32, ptr, i32, i32, i32, ptr, i32)
// CHECK: declare void @__tgt_interop_use(ptr, i32, ptr, i32, i32, ptr, i32)
// CHECK: declare void @__tgt_interop_destroy(ptr, i32, ptr, i32, i32, ptr, i32)

View file

@ -40,6 +40,8 @@
integer, parameter, public :: omp_alloctrait_val_kind = c_intptr_t
integer, parameter, public :: omp_interop_kind = c_intptr_t
integer, parameter, public :: omp_interop_fr_kind = omp_integer_kind
integer, parameter, public :: omp_interop_property_kind = omp_integer_kind
integer, parameter, public :: omp_interop_rc_kind = omp_integer_kind
type omp_alloctrait
integer(kind=omp_alloctrait_key_kind) key
@ -84,6 +86,8 @@
public :: omp_alloctrait_val_kind
public :: omp_interop_kind
public :: omp_interop_fr_kind
public :: omp_interop_property_kind
public :: omp_interop_rc_kind
public :: omp_alloctrait
public :: omp_pause_resource_kind
public :: omp_depend_kind
@ -218,6 +222,28 @@
integer (kind=omp_interop_kind), parameter, public :: omp_interop_none = 0
! interop property constants
integer (kind=omp_interop_property_kind), parameter, public :: omp_ipr_fr_id = -1
integer (kind=omp_interop_property_kind), parameter, public :: omp_ipr_fr_name = -2
integer (kind=omp_interop_property_kind), parameter, public :: omp_ipr_vendor = -3
integer (kind=omp_interop_property_kind), parameter, public :: omp_ipr_vendor_name = -4
integer (kind=omp_interop_property_kind), parameter, public :: omp_ipr_device_num = -5
integer (kind=omp_interop_property_kind), parameter, public :: omp_ipr_platform = -6
integer (kind=omp_interop_property_kind), parameter, public :: omp_ipr_device = -7
integer (kind=omp_interop_property_kind), parameter, public :: omp_ipr_device_context = -8
integer (kind=omp_interop_property_kind), parameter, public :: omp_ipr_targetsync = -9
integer (kind=omp_interop_property_kind), parameter, public :: omp_ipr_first = -9
! interop return code constants
integer (kind=omp_interop_rc_kind), parameter, public :: omp_irc_no_value = 1
integer (kind=omp_interop_rc_kind), parameter, public :: omp_irc_success = 0
integer (kind=omp_interop_rc_kind), parameter, public :: omp_irc_empty = -1
integer (kind=omp_interop_rc_kind), parameter, public :: omp_irc_out_of_range = -2
integer (kind=omp_interop_rc_kind), parameter, public :: omp_irc_type_int = -3
integer (kind=omp_interop_rc_kind), parameter, public :: omp_irc_type_ptr = -4
integer (kind=omp_interop_rc_kind), parameter, public :: omp_irc_type_str = -5
integer (kind=omp_interop_rc_kind), parameter, public :: omp_irc_other = -6
interface
! ***
@ -1061,6 +1087,67 @@
logical (kind=omp_logical_kind) kmp_get_cancellation_status
end function kmp_get_cancellation_status
! ***
! *** interop query routines
! ***
function omp_get_num_interop_properties(interop) bind(c)
use omp_lib_kinds
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_integer_kind) omp_get_num_interop_properties
end function omp_get_num_interop_properties
function omp_get_interop_int(interop, property_id, err) bind(c)
use omp_lib_kinds
use, intrinsic :: iso_c_binding, only: c_intptr_t, c_int
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_interop_property_kind), value :: property_id
integer (kind=c_int) :: err
integer (kind=c_intptr_t) omp_get_interop_int
end function omp_get_interop_int
function omp_get_interop_ptr(interop, property_id, err) bind(c)
use omp_lib_kinds
use, intrinsic :: iso_c_binding, only: c_ptr, c_int
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_interop_property_kind), value :: property_id
integer (kind=c_int) :: err
type(c_ptr) omp_get_interop_ptr
end function omp_get_interop_ptr
function omp_get_interop_str(interop, property_id, err) bind(c)
use omp_lib_kinds
use, intrinsic :: iso_c_binding, only: c_ptr, c_int
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_interop_property_kind), value :: property_id
integer (kind=c_int) :: err
type(c_ptr) omp_get_interop_str
end function omp_get_interop_str
function omp_get_interop_name(interop, property_id) bind(c)
use omp_lib_kinds
use, intrinsic :: iso_c_binding, only: c_ptr
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_interop_property_kind), value :: property_id
type(c_ptr) omp_get_interop_name
end function omp_get_interop_name
function omp_get_interop_type_desc(interop, property_id) bind(c)
use omp_lib_kinds
use, intrinsic :: iso_c_binding, only: c_ptr
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_interop_property_kind), value :: property_id
type(c_ptr) omp_get_interop_type_desc
end function omp_get_interop_type_desc
function omp_get_interop_rc_desc(interop, ret_code) bind(c)
use omp_lib_kinds
use, intrinsic :: iso_c_binding, only: c_ptr
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_interop_rc_kind), value :: ret_code
type(c_ptr) omp_get_interop_rc_desc
end function omp_get_interop_rc_desc
end interface
! make the above routine definitions public
@ -1182,5 +1269,12 @@
public :: kmp_set_warnings_on
public :: kmp_set_warnings_off
public :: kmp_get_cancellation_status
public :: omp_get_num_interop_properties
public :: omp_get_interop_int
public :: omp_get_interop_ptr
public :: omp_get_interop_str
public :: omp_get_interop_name
public :: omp_get_interop_type_desc
public :: omp_get_interop_rc_desc
end module omp_lib

View file

@ -56,6 +56,10 @@
parameter(omp_interop_kind=int_ptr_kind())
integer omp_interop_fr_kind
parameter(omp_interop_fr_kind=omp_integer_kind)
integer omp_interop_property_kind
parameter(omp_interop_property_kind=omp_integer_kind)
integer omp_interop_rc_kind
parameter(omp_interop_rc_kind=omp_integer_kind)
integer(kind=omp_integer_kind)openmp_version
parameter(openmp_version=@LIBOMP_OMP_YEAR_MONTH@)
@ -296,6 +300,46 @@
integer(kind=omp_interop_kind)omp_interop_none
parameter(omp_interop_none=0)
! interop property constants
integer(kind=omp_interop_property_kind)omp_ipr_fr_id
parameter(omp_ipr_fr_id=-1)
integer(kind=omp_interop_property_kind)omp_ipr_fr_name
parameter(omp_ipr_fr_name=-2)
integer(kind=omp_interop_property_kind)omp_ipr_vendor
parameter(omp_ipr_vendor=-3)
integer(kind=omp_interop_property_kind)omp_ipr_vendor_name
parameter(omp_ipr_vendor_name=-4)
integer(kind=omp_interop_property_kind)omp_ipr_device_num
parameter(omp_ipr_device_num=-5)
integer(kind=omp_interop_property_kind)omp_ipr_platform
parameter(omp_ipr_platform=-6)
integer(kind=omp_interop_property_kind)omp_ipr_device
parameter(omp_ipr_device=-7)
integer(kind=omp_interop_property_kind)omp_ipr_device_context
parameter(omp_ipr_device_context=-8)
integer(kind=omp_interop_property_kind)omp_ipr_targetsync
parameter(omp_ipr_targetsync=-9)
integer(kind=omp_interop_property_kind)omp_ipr_first
parameter(omp_ipr_first=-9)
! interop return code constants
integer(kind=omp_interop_rc_kind)omp_irc_no_value
parameter(omp_irc_no_value=1)
integer(kind=omp_interop_rc_kind)omp_irc_success
parameter(omp_irc_success=0)
integer(kind=omp_interop_rc_kind)omp_irc_empty
parameter(omp_irc_empty=-1)
integer(kind=omp_interop_rc_kind)omp_irc_out_of_range
parameter(omp_irc_out_of_range=-2)
integer(kind=omp_interop_rc_kind)omp_irc_type_int
parameter(omp_irc_type_int=-3)
integer(kind=omp_interop_rc_kind)omp_irc_type_ptr
parameter(omp_irc_type_ptr=-4)
integer(kind=omp_interop_rc_kind)omp_irc_type_str
parameter(omp_irc_type_str=-5)
integer(kind=omp_interop_rc_kind)omp_irc_other
parameter(omp_irc_other=-6)
interface
! ***
@ -1129,6 +1173,67 @@
subroutine kmp_set_warnings_off() bind(c)
end subroutine kmp_set_warnings_off
! ***
! *** interop query routines
! ***
function omp_get_num_interop_properties(interop) bind(c)
import
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_integer_kind) omp_get_num_interop_properties
end function omp_get_num_interop_properties
function omp_get_interop_int(interop, property_id, err) bind(c)
use, intrinsic :: iso_c_binding, only: c_intptr_t, c_int
import
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_interop_property_kind), value :: property_id
integer (kind=c_int) :: err
integer (kind=c_intptr_t) omp_get_interop_int
end function omp_get_interop_int
function omp_get_interop_ptr(interop, property_id, err) bind(c)
use, intrinsic :: iso_c_binding, only: c_ptr, c_int
import
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_interop_property_kind), value :: property_id
integer (kind=c_int) :: err
type(c_ptr) omp_get_interop_ptr
end function omp_get_interop_ptr
function omp_get_interop_str(interop, property_id, err) bind(c)
use, intrinsic :: iso_c_binding, only: c_ptr, c_int
import
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_interop_property_kind), value :: property_id
integer (kind=c_int) :: err
type(c_ptr) omp_get_interop_str
end function omp_get_interop_str
function omp_get_interop_name(interop, property_id) bind(c)
use, intrinsic :: iso_c_binding, only: c_ptr
import
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_interop_property_kind), value :: property_id
type(c_ptr) omp_get_interop_name
end function omp_get_interop_name
function omp_get_interop_type_desc(interop, property_id) bind(c)
use, intrinsic :: iso_c_binding, only: c_ptr
import
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_interop_property_kind), value :: property_id
type(c_ptr) omp_get_interop_type_desc
end function omp_get_interop_type_desc
function omp_get_interop_rc_desc(interop, ret_code) bind(c)
use, intrinsic :: iso_c_binding, only: c_ptr
import
integer (kind=omp_interop_kind), value :: interop
integer (kind=omp_interop_rc_kind), value :: ret_code
type(c_ptr) omp_get_interop_rc_desc
end function omp_get_interop_rc_desc
end interface
#ifdef __INTEL_COMPILER