Skip to content

Commit f687ed9

Browse files
authored
[Flang][OpenMP] Initial defaultmap implementation (#135226)
This aims to implement most of the initial arguments for defaultmap aside from firstprivate and none, and some of the more recent OpenMP 6 additions which will come in subsequent updates (with the OpenMP 6 variants needing parsing/semantic support first).
1 parent db42345 commit f687ed9

File tree

13 files changed

+532
-73
lines changed

13 files changed

+532
-73
lines changed

flang/include/flang/Parser/parse-tree.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4149,8 +4149,8 @@ struct OmpDefaultClause {
41494149
// PRESENT // since 5.1
41504150
struct OmpDefaultmapClause {
41514151
TUPLE_CLASS_BOILERPLATE(OmpDefaultmapClause);
4152-
ENUM_CLASS(
4153-
ImplicitBehavior, Alloc, To, From, Tofrom, Firstprivate, None, Default)
4152+
ENUM_CLASS(ImplicitBehavior, Alloc, To, From, Tofrom, Firstprivate, None,
4153+
Default, Present)
41544154
MODIFIER_BOILERPLATE(OmpVariableCategory);
41554155
std::tuple<ImplicitBehavior, MODIFIERS()> t;
41564156
};

flang/lib/Lower/OpenMP/ClauseProcessor.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,26 @@ static bool isVectorSubscript(const evaluate::Expr<T> &expr) {
877877
return false;
878878
}
879879

880+
bool ClauseProcessor::processDefaultMap(lower::StatementContext &stmtCtx,
881+
DefaultMapsTy &result) const {
882+
auto process = [&](const omp::clause::Defaultmap &clause,
883+
const parser::CharBlock &) {
884+
using Defmap = omp::clause::Defaultmap;
885+
clause::Defaultmap::VariableCategory variableCategory =
886+
Defmap::VariableCategory::All;
887+
// Variable Category is optional, if not specified defaults to all.
888+
// Multiples of the same category are illegal as are any other
889+
// defaultmaps being specified when a user specified all is in place,
890+
// however, this should be handled earlier during semantics.
891+
if (auto varCat =
892+
std::get<std::optional<Defmap::VariableCategory>>(clause.t))
893+
variableCategory = varCat.value();
894+
auto behaviour = std::get<Defmap::ImplicitBehavior>(clause.t);
895+
result[variableCategory] = behaviour;
896+
};
897+
return findRepeatableClause<omp::clause::Defaultmap>(process);
898+
}
899+
880900
bool ClauseProcessor::processDepend(lower::SymMap &symMap,
881901
lower::StatementContext &stmtCtx,
882902
mlir::omp::DependClauseOps &result) const {

flang/lib/Lower/OpenMP/ClauseProcessor.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ namespace Fortran {
3232
namespace lower {
3333
namespace omp {
3434

35+
// Container type for tracking user specified Defaultmaps for a target region
36+
using DefaultMapsTy = std::map<clause::Defaultmap::VariableCategory,
37+
clause::Defaultmap::ImplicitBehavior>;
38+
3539
/// Class that handles the processing of OpenMP clauses.
3640
///
3741
/// Its `process<ClauseName>()` methods perform MLIR code generation for their
@@ -110,6 +114,8 @@ class ClauseProcessor {
110114
bool processCopyin() const;
111115
bool processCopyprivate(mlir::Location currentLocation,
112116
mlir::omp::CopyprivateClauseOps &result) const;
117+
bool processDefaultMap(lower::StatementContext &stmtCtx,
118+
DefaultMapsTy &result) const;
113119
bool processDepend(lower::SymMap &symMap, lower::StatementContext &stmtCtx,
114120
mlir::omp::DependClauseOps &result) const;
115121
bool

flang/lib/Lower/OpenMP/Clauses.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ Defaultmap make(const parser::OmpClause::Defaultmap &inp,
612612
MS(Firstprivate, Firstprivate)
613613
MS(None, None)
614614
MS(Default, Default)
615-
// MS(, Present) missing-in-parser
615+
MS(Present, Present)
616616
// clang-format on
617617
);
618618

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 157 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,145 @@ static void genLoopVars(
980980
firOpBuilder.setInsertionPointAfter(storeOp);
981981
}
982982

983+
static clause::Defaultmap::ImplicitBehavior
984+
getDefaultmapIfPresent(DefaultMapsTy &defaultMaps, mlir::Type varType) {
985+
using DefMap = clause::Defaultmap;
986+
987+
if (defaultMaps.empty())
988+
return DefMap::ImplicitBehavior::Default;
989+
990+
if (llvm::is_contained(defaultMaps, DefMap::VariableCategory::All))
991+
return defaultMaps[DefMap::VariableCategory::All];
992+
993+
// NOTE: Unsure if complex and/or vector falls into a scalar type
994+
// or aggregate, but the current default implicit behaviour is to
995+
// treat them as such (c_ptr has its own behaviour, so perhaps
996+
// being lumped in as a scalar isn't the right thing).
997+
if ((fir::isa_trivial(varType) || fir::isa_char(varType) ||
998+
fir::isa_builtin_cptr_type(varType)) &&
999+
llvm::is_contained(defaultMaps, DefMap::VariableCategory::Scalar))
1000+
return defaultMaps[DefMap::VariableCategory::Scalar];
1001+
1002+
if (fir::isPointerType(varType) &&
1003+
llvm::is_contained(defaultMaps, DefMap::VariableCategory::Pointer))
1004+
return defaultMaps[DefMap::VariableCategory::Pointer];
1005+
1006+
if (fir::isAllocatableType(varType) &&
1007+
llvm::is_contained(defaultMaps, DefMap::VariableCategory::Allocatable))
1008+
return defaultMaps[DefMap::VariableCategory::Allocatable];
1009+
1010+
if (fir::isa_aggregate(varType) &&
1011+
llvm::is_contained(defaultMaps, DefMap::VariableCategory::Aggregate))
1012+
return defaultMaps[DefMap::VariableCategory::Aggregate];
1013+
1014+
return DefMap::ImplicitBehavior::Default;
1015+
}
1016+
1017+
static std::pair<llvm::omp::OpenMPOffloadMappingFlags,
1018+
mlir::omp::VariableCaptureKind>
1019+
getImplicitMapTypeAndKind(fir::FirOpBuilder &firOpBuilder,
1020+
lower::AbstractConverter &converter,
1021+
DefaultMapsTy &defaultMaps, mlir::Type varType,
1022+
mlir::Location loc, const semantics::Symbol &sym) {
1023+
using DefMap = clause::Defaultmap;
1024+
// Check if a value of type `type` can be passed to the kernel by value.
1025+
// All kernel parameters are of pointer type, so if the value can be
1026+
// represented inside of a pointer, then it can be passed by value.
1027+
auto isLiteralType = [&](mlir::Type type) {
1028+
const mlir::DataLayout &dl = firOpBuilder.getDataLayout();
1029+
mlir::Type ptrTy =
1030+
mlir::LLVM::LLVMPointerType::get(&converter.getMLIRContext());
1031+
uint64_t ptrSize = dl.getTypeSize(ptrTy);
1032+
uint64_t ptrAlign = dl.getTypePreferredAlignment(ptrTy);
1033+
1034+
auto [size, align] = fir::getTypeSizeAndAlignmentOrCrash(
1035+
loc, type, dl, converter.getKindMap());
1036+
return size <= ptrSize && align <= ptrAlign;
1037+
};
1038+
1039+
llvm::omp::OpenMPOffloadMappingFlags mapFlag =
1040+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
1041+
1042+
auto implicitBehaviour = getDefaultmapIfPresent(defaultMaps, varType);
1043+
if (implicitBehaviour == DefMap::ImplicitBehavior::Default) {
1044+
mlir::omp::VariableCaptureKind captureKind =
1045+
mlir::omp::VariableCaptureKind::ByRef;
1046+
1047+
// If a variable is specified in declare target link and if device
1048+
// type is not specified as `nohost`, it needs to be mapped tofrom
1049+
mlir::ModuleOp mod = firOpBuilder.getModule();
1050+
mlir::Operation *op = mod.lookupSymbol(converter.mangleName(sym));
1051+
auto declareTargetOp =
1052+
llvm::dyn_cast_if_present<mlir::omp::DeclareTargetInterface>(op);
1053+
if (declareTargetOp && declareTargetOp.isDeclareTarget()) {
1054+
if (declareTargetOp.getDeclareTargetCaptureClause() ==
1055+
mlir::omp::DeclareTargetCaptureClause::link &&
1056+
declareTargetOp.getDeclareTargetDeviceType() !=
1057+
mlir::omp::DeclareTargetDeviceType::nohost) {
1058+
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
1059+
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
1060+
}
1061+
} else if (fir::isa_trivial(varType) || fir::isa_char(varType)) {
1062+
// Scalars behave as if they were "firstprivate".
1063+
// TODO: Handle objects that are shared/lastprivate or were listed
1064+
// in an in_reduction clause.
1065+
if (isLiteralType(varType)) {
1066+
captureKind = mlir::omp::VariableCaptureKind::ByCopy;
1067+
} else {
1068+
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
1069+
}
1070+
} else if (!fir::isa_builtin_cptr_type(varType)) {
1071+
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
1072+
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
1073+
}
1074+
return std::make_pair(mapFlag, captureKind);
1075+
}
1076+
1077+
switch (implicitBehaviour) {
1078+
case DefMap::ImplicitBehavior::Alloc:
1079+
return std::make_pair(llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE,
1080+
mlir::omp::VariableCaptureKind::ByRef);
1081+
break;
1082+
case DefMap::ImplicitBehavior::Firstprivate:
1083+
case DefMap::ImplicitBehavior::None:
1084+
TODO(loc, "Firstprivate and None are currently unsupported defaultmap "
1085+
"behaviour");
1086+
break;
1087+
case DefMap::ImplicitBehavior::From:
1088+
return std::make_pair(mapFlag |=
1089+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM,
1090+
mlir::omp::VariableCaptureKind::ByRef);
1091+
break;
1092+
case DefMap::ImplicitBehavior::Present:
1093+
return std::make_pair(mapFlag |=
1094+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PRESENT,
1095+
mlir::omp::VariableCaptureKind::ByRef);
1096+
break;
1097+
case DefMap::ImplicitBehavior::To:
1098+
return std::make_pair(mapFlag |=
1099+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO,
1100+
(fir::isa_trivial(varType) || fir::isa_char(varType))
1101+
? mlir::omp::VariableCaptureKind::ByCopy
1102+
: mlir::omp::VariableCaptureKind::ByRef);
1103+
break;
1104+
case DefMap::ImplicitBehavior::Tofrom:
1105+
return std::make_pair(mapFlag |=
1106+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM |
1107+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO,
1108+
mlir::omp::VariableCaptureKind::ByRef);
1109+
break;
1110+
case DefMap::ImplicitBehavior::Default:
1111+
llvm_unreachable(
1112+
"Implicit None Behaviour Should Have Been Handled Earlier");
1113+
break;
1114+
}
1115+
1116+
return std::make_pair(mapFlag |=
1117+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM |
1118+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO,
1119+
mlir::omp::VariableCaptureKind::ByRef);
1120+
}
1121+
9831122
static void
9841123
markDeclareTarget(mlir::Operation *op, lower::AbstractConverter &converter,
9851124
mlir::omp::DeclareTargetCaptureClause captureClause,
@@ -1677,11 +1816,13 @@ static void genTargetClauses(
16771816
lower::SymMap &symTable, lower::StatementContext &stmtCtx,
16781817
lower::pft::Evaluation &eval, const List<Clause> &clauses,
16791818
mlir::Location loc, mlir::omp::TargetOperands &clauseOps,
1819+
DefaultMapsTy &defaultMaps,
16801820
llvm::SmallVectorImpl<const semantics::Symbol *> &hasDeviceAddrSyms,
16811821
llvm::SmallVectorImpl<const semantics::Symbol *> &isDevicePtrSyms,
16821822
llvm::SmallVectorImpl<const semantics::Symbol *> &mapSyms) {
16831823
ClauseProcessor cp(converter, semaCtx, clauses);
16841824
cp.processBare(clauseOps);
1825+
cp.processDefaultMap(stmtCtx, defaultMaps);
16851826
cp.processDepend(symTable, stmtCtx, clauseOps);
16861827
cp.processDevice(stmtCtx, clauseOps);
16871828
cp.processHasDeviceAddr(stmtCtx, clauseOps, hasDeviceAddrSyms);
@@ -1696,9 +1837,8 @@ static void genTargetClauses(
16961837
cp.processNowait(clauseOps);
16971838
cp.processThreadLimit(stmtCtx, clauseOps);
16981839

1699-
cp.processTODO<clause::Allocate, clause::Defaultmap, clause::InReduction,
1700-
clause::UsesAllocators>(loc,
1701-
llvm::omp::Directive::OMPD_target);
1840+
cp.processTODO<clause::Allocate, clause::InReduction, clause::UsesAllocators>(
1841+
loc, llvm::omp::Directive::OMPD_target);
17021842

17031843
// `target private(..)` is only supported in delayed privatization mode.
17041844
if (!enableDelayedPrivatizationStaging)
@@ -2242,32 +2382,19 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
22422382
hostEvalInfo.emplace_back();
22432383

22442384
mlir::omp::TargetOperands clauseOps;
2385+
DefaultMapsTy defaultMaps;
22452386
llvm::SmallVector<const semantics::Symbol *> mapSyms, isDevicePtrSyms,
22462387
hasDeviceAddrSyms;
22472388
genTargetClauses(converter, semaCtx, symTable, stmtCtx, eval, item->clauses,
2248-
loc, clauseOps, hasDeviceAddrSyms, isDevicePtrSyms, mapSyms);
2389+
loc, clauseOps, defaultMaps, hasDeviceAddrSyms,
2390+
isDevicePtrSyms, mapSyms);
22492391

22502392
DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval,
22512393
/*shouldCollectPreDeterminedSymbols=*/
22522394
lower::omp::isLastItemInQueue(item, queue),
22532395
/*useDelayedPrivatization=*/true, symTable);
22542396
dsp.processStep1(&clauseOps);
22552397

2256-
// Check if a value of type `type` can be passed to the kernel by value.
2257-
// All kernel parameters are of pointer type, so if the value can be
2258-
// represented inside of a pointer, then it can be passed by value.
2259-
auto isLiteralType = [&](mlir::Type type) {
2260-
const mlir::DataLayout &dl = firOpBuilder.getDataLayout();
2261-
mlir::Type ptrTy =
2262-
mlir::LLVM::LLVMPointerType::get(&converter.getMLIRContext());
2263-
uint64_t ptrSize = dl.getTypeSize(ptrTy);
2264-
uint64_t ptrAlign = dl.getTypePreferredAlignment(ptrTy);
2265-
2266-
auto [size, align] = fir::getTypeSizeAndAlignmentOrCrash(
2267-
loc, type, dl, converter.getKindMap());
2268-
return size <= ptrSize && align <= ptrAlign;
2269-
};
2270-
22712398
// 5.8.1 Implicit Data-Mapping Attribute Rules
22722399
// The following code follows the implicit data-mapping rules to map all the
22732400
// symbols used inside the region that do not have explicit data-environment
@@ -2330,56 +2457,25 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
23302457
firOpBuilder, info, dataExv,
23312458
semantics::IsAssumedSizeArray(sym.GetUltimate()),
23322459
converter.getCurrentLocation());
2333-
2334-
llvm::omp::OpenMPOffloadMappingFlags mapFlag =
2335-
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
2336-
mlir::omp::VariableCaptureKind captureKind =
2337-
mlir::omp::VariableCaptureKind::ByRef;
2338-
23392460
mlir::Value baseOp = info.rawInput;
23402461
mlir::Type eleType = baseOp.getType();
23412462
if (auto refType = mlir::dyn_cast<fir::ReferenceType>(baseOp.getType()))
23422463
eleType = refType.getElementType();
23432464

2344-
// If a variable is specified in declare target link and if device
2345-
// type is not specified as `nohost`, it needs to be mapped tofrom
2346-
mlir::ModuleOp mod = firOpBuilder.getModule();
2347-
mlir::Operation *op = mod.lookupSymbol(converter.mangleName(sym));
2348-
auto declareTargetOp =
2349-
llvm::dyn_cast_if_present<mlir::omp::DeclareTargetInterface>(op);
2350-
if (declareTargetOp && declareTargetOp.isDeclareTarget()) {
2351-
if (declareTargetOp.getDeclareTargetCaptureClause() ==
2352-
mlir::omp::DeclareTargetCaptureClause::link &&
2353-
declareTargetOp.getDeclareTargetDeviceType() !=
2354-
mlir::omp::DeclareTargetDeviceType::nohost) {
2355-
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
2356-
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
2357-
}
2358-
} else if (fir::isa_trivial(eleType) || fir::isa_char(eleType)) {
2359-
// Scalars behave as if they were "firstprivate".
2360-
// TODO: Handle objects that are shared/lastprivate or were listed
2361-
// in an in_reduction clause.
2362-
if (isLiteralType(eleType)) {
2363-
captureKind = mlir::omp::VariableCaptureKind::ByCopy;
2364-
} else {
2365-
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
2366-
}
2367-
} else if (!fir::isa_builtin_cptr_type(eleType)) {
2368-
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
2369-
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
2370-
}
2371-
auto location =
2372-
mlir::NameLoc::get(mlir::StringAttr::get(firOpBuilder.getContext(),
2373-
sym.name().ToString()),
2374-
baseOp.getLoc());
2465+
std::pair<llvm::omp::OpenMPOffloadMappingFlags,
2466+
mlir::omp::VariableCaptureKind>
2467+
mapFlagAndKind = getImplicitMapTypeAndKind(
2468+
firOpBuilder, converter, defaultMaps, eleType, loc, sym);
2469+
23752470
mlir::Value mapOp = createMapInfoOp(
2376-
firOpBuilder, location, baseOp, /*varPtrPtr=*/mlir::Value{},
2377-
name.str(), bounds, /*members=*/{},
2471+
firOpBuilder, converter.getCurrentLocation(), baseOp,
2472+
/*varPtrPtr=*/mlir::Value{}, name.str(), bounds, /*members=*/{},
23782473
/*membersIndex=*/mlir::ArrayAttr{},
23792474
static_cast<
23802475
std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
2381-
mapFlag),
2382-
captureKind, baseOp.getType(), /*partialMap=*/false, mapperId);
2476+
std::get<0>(mapFlagAndKind)),
2477+
std::get<1>(mapFlagAndKind), baseOp.getType(),
2478+
/*partialMap=*/false, mapperId);
23832479

23842480
clauseOps.mapVars.push_back(mapOp);
23852481
mapSyms.push_back(&sym);
@@ -4199,6 +4295,7 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
41994295
!std::holds_alternative<clause::Copyin>(clause.u) &&
42004296
!std::holds_alternative<clause::Copyprivate>(clause.u) &&
42014297
!std::holds_alternative<clause::Default>(clause.u) &&
4298+
!std::holds_alternative<clause::Defaultmap>(clause.u) &&
42024299
!std::holds_alternative<clause::Depend>(clause.u) &&
42034300
!std::holds_alternative<clause::Filter>(clause.u) &&
42044301
!std::holds_alternative<clause::Final>(clause.u) &&

flang/lib/Parser/openmp-parsers.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ TYPE_PARSER(construct<OmpMapClause>(
705705
// [OpenMP 5.0]
706706
// 2.19.7.2 defaultmap(implicit-behavior[:variable-category])
707707
// implicit-behavior -> ALLOC | TO | FROM | TOFROM | FIRSRTPRIVATE | NONE |
708-
// DEFAULT
708+
// DEFAULT | PRESENT
709709
// variable-category -> ALL | SCALAR | AGGREGATE | ALLOCATABLE | POINTER
710710
TYPE_PARSER(construct<OmpDefaultmapClause>(
711711
construct<OmpDefaultmapClause::ImplicitBehavior>(
@@ -716,7 +716,8 @@ TYPE_PARSER(construct<OmpDefaultmapClause>(
716716
"FIRSTPRIVATE" >>
717717
pure(OmpDefaultmapClause::ImplicitBehavior::Firstprivate) ||
718718
"NONE" >> pure(OmpDefaultmapClause::ImplicitBehavior::None) ||
719-
"DEFAULT" >> pure(OmpDefaultmapClause::ImplicitBehavior::Default)),
719+
"DEFAULT" >> pure(OmpDefaultmapClause::ImplicitBehavior::Default) ||
720+
"PRESENT" >> pure(OmpDefaultmapClause::ImplicitBehavior::Present)),
720721
maybe(":" >> nonemptyList(Parser<OmpDefaultmapClause::Modifier>{}))))
721722

722723
TYPE_PARSER(construct<OmpScheduleClause::Kind>(
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
!RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s
2+
!RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s
3+
4+
subroutine f00
5+
implicit none
6+
integer :: i
7+
!CHECK: not yet implemented: Firstprivate and None are currently unsupported defaultmap behaviour
8+
!$omp target defaultmap(firstprivate)
9+
i = 10
10+
!$omp end target
11+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
!RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s
2+
!RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s
3+
4+
subroutine f00
5+
implicit none
6+
integer :: i
7+
!CHECK: not yet implemented: Firstprivate and None are currently unsupported defaultmap behaviour
8+
!$omp target defaultmap(none)
9+
i = 10
10+
!$omp end target
11+
end

0 commit comments

Comments
 (0)