diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp index 2ac4d9548b65b..de69a670ad335 100644 --- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp +++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp @@ -43,16 +43,26 @@ bool DataSharingProcessor::OMPConstructSymbolVisitor::isSymbolDefineBy( [](const auto &functionParserNode) { return false; }}); } +static bool isConstructWithTopLevelTarget(lower::pft::Evaluation &eval) { + const auto *ompEval = eval.getIf(); + if (ompEval) { + auto dir = parser::omp::GetOmpDirectiveName(ompEval).v; + if (llvm::omp::topTargetSet.test(dir)) + return true; + } + return false; +} + DataSharingProcessor::DataSharingProcessor( lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx, const List &clauses, lower::pft::Evaluation &eval, bool shouldCollectPreDeterminedSymbols, bool useDelayedPrivatization, - lower::SymMap &symTable) + lower::SymMap &symTable, bool isTargetPrivatization) : converter(converter), semaCtx(semaCtx), firOpBuilder(converter.getFirOpBuilder()), clauses(clauses), eval(eval), shouldCollectPreDeterminedSymbols(shouldCollectPreDeterminedSymbols), useDelayedPrivatization(useDelayedPrivatization), symTable(symTable), - visitor(semaCtx) { + isTargetPrivatization(isTargetPrivatization), visitor(semaCtx) { eval.visit([&](const auto &functionParserNode) { parser::Walk(functionParserNode, visitor); }); @@ -62,10 +72,12 @@ DataSharingProcessor::DataSharingProcessor(lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval, bool useDelayedPrivatization, - lower::SymMap &symTable) + lower::SymMap &symTable, + bool isTargetPrivatization) : DataSharingProcessor(converter, semaCtx, {}, eval, /*shouldCollectPreDeterminedSymols=*/false, - useDelayedPrivatization, symTable) {} + useDelayedPrivatization, symTable, + isTargetPrivatization) {} void DataSharingProcessor::processStep1( mlir::omp::PrivateClauseOps *clauseOps) { @@ -552,8 +564,19 @@ void DataSharingProcessor::collectSymbols( }; auto shouldCollectSymbol = [&](const semantics::Symbol *sym) { - if (collectImplicit) + if (collectImplicit) { + // If we're a combined construct with a target region, implicit + // firstprivate captures, should only belong to the target region + // and not be added/captured by later directives. Parallel regions + // will likely want the same captures to be shared and for SIMD it's + // illegal to have firstprivate clauses. + if (isConstructWithTopLevelTarget(eval) && !isTargetPrivatization && + sym->test(semantics::Symbol::Flag::OmpFirstPrivate)) { + return false; + } + return sym->test(semantics::Symbol::Flag::OmpImplicit); + } if (collectPreDetermined) return sym->test(semantics::Symbol::Flag::OmpPreDetermined); diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.h b/flang/lib/Lower/OpenMP/DataSharingProcessor.h index bc422f410403a..96e7fa6d5d93c 100644 --- a/flang/lib/Lower/OpenMP/DataSharingProcessor.h +++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.h @@ -93,6 +93,7 @@ class DataSharingProcessor { bool useDelayedPrivatization; llvm::SmallSet mightHaveReadHostSym; lower::SymMap &symTable; + bool isTargetPrivatization; OMPConstructSymbolVisitor visitor; bool needBarrier(); @@ -130,12 +131,14 @@ class DataSharingProcessor { const List &clauses, lower::pft::Evaluation &eval, bool shouldCollectPreDeterminedSymbols, - bool useDelayedPrivatization, lower::SymMap &symTable); + bool useDelayedPrivatization, lower::SymMap &symTable, + bool isTargetPrivatization = false); DataSharingProcessor(lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval, - bool useDelayedPrivatization, lower::SymMap &symTable); + bool useDelayedPrivatization, lower::SymMap &symTable, + bool isTargetPrivatization = false); // Privatisation is split into two steps. // Step1 performs cloning of all privatisation clauses and copying for diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 6a4ec77ca071e..c7bbd944b431d 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -2473,6 +2473,33 @@ genSingleOp(lower::AbstractConverter &converter, lower::SymMap &symTable, queue, item, clauseOps); } +static bool isDuplicateMappedSymbol( + const semantics::Symbol &sym, + const llvm::SetVector &privatizedSyms, + const llvm::SmallVectorImpl &hasDevSyms, + const llvm::SmallVectorImpl &mappedSyms) { + llvm::SmallVector concatSyms; + concatSyms.reserve(privatizedSyms.size() + hasDevSyms.size() + + mappedSyms.size()); + concatSyms.append(privatizedSyms.begin(), privatizedSyms.end()); + concatSyms.append(hasDevSyms.begin(), hasDevSyms.end()); + concatSyms.append(mappedSyms.begin(), mappedSyms.end()); + + auto checkSymbol = [&](const semantics::Symbol &checkSym) { + return std::any_of(concatSyms.begin(), concatSyms.end(), + [&](auto v) { return v->GetUltimate() == checkSym; }); + }; + + if (checkSymbol(sym)) + return true; + + const auto *hostAssoc{sym.detailsIf()}; + if (hostAssoc && checkSymbol(hostAssoc->symbol())) + return true; + + return checkSymbol(sym.GetUltimate()); +} + static mlir::omp::TargetOp genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable, lower::StatementContext &stmtCtx, @@ -2499,7 +2526,8 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable, DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval, /*shouldCollectPreDeterminedSymbols=*/ lower::omp::isLastItemInQueue(item, queue), - /*useDelayedPrivatization=*/true, symTable); + /*useDelayedPrivatization=*/true, symTable, + /*isTargetPrivitization=*/true); dsp.processStep1(&clauseOps); // 5.8.1 Implicit Data-Mapping Attribute Rules @@ -2508,17 +2536,6 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable, // attribute clauses (neither data-sharing; e.g. `private`, nor `map` // clauses). auto captureImplicitMap = [&](const semantics::Symbol &sym) { - if (dsp.getAllSymbolsToPrivatize().contains(&sym)) - return; - - // Skip parameters/constants as they do not need to be mapped. - if (semantics::IsNamedConstant(sym)) - return; - - // These symbols are mapped individually in processHasDeviceAddr. - if (llvm::is_contained(hasDeviceAddrSyms, &sym)) - return; - // Structure component symbols don't have bindings, and can only be // explicitly mapped individually. If a member is captured implicitly // we map the entirety of the derived type when we find its symbol. @@ -2540,7 +2557,12 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable, if (!converter.getSymbolAddress(sym)) return; - if (!llvm::is_contained(mapSyms, &sym)) { + // Skip parameters/constants as they do not need to be mapped. + if (semantics::IsNamedConstant(sym)) + return; + + if (!isDuplicateMappedSymbol(sym, dsp.getAllSymbolsToPrivatize(), + hasDeviceAddrSyms, mapSyms)) { if (const auto *details = sym.template detailsIf()) converter.copySymbolBinding(details->symbol(), sym); diff --git a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp index 3a802ef0a96cb..970f7d7ab063f 100644 --- a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp +++ b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp @@ -55,6 +55,20 @@ class MapsForPrivatizedSymbolsPass omp::MapInfoOp createMapInfo(Location loc, Value var, fir::FirOpBuilder &builder) { + // Check if a value of type `type` can be passed to the kernel by value. + // All kernel parameters are of pointer type, so if the value can be + // represented inside of a pointer, then it can be passed by value. + auto canPassByValue = [&](mlir::Type type) { + const mlir::DataLayout &dl = builder.getDataLayout(); + mlir::Type ptrTy = mlir::LLVM::LLVMPointerType::get(builder.getContext()); + uint64_t ptrSize = dl.getTypeSize(ptrTy); + uint64_t ptrAlign = dl.getTypePreferredAlignment(ptrTy); + + auto [size, align] = fir::getTypeSizeAndAlignmentOrCrash( + loc, type, dl, builder.getKindMap()); + return size <= ptrSize && align <= ptrAlign; + }; + uint64_t mapTypeTo = static_cast< std::underlying_type_t>( llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO); @@ -94,14 +108,22 @@ class MapsForPrivatizedSymbolsPass if (needsBoundsOps(varPtr)) genBoundsOps(builder, varPtr, boundsOps); + mlir::omp::VariableCaptureKind captureKind = + mlir::omp::VariableCaptureKind::ByRef; + if (fir::isa_trivial(fir::unwrapRefType(varPtr.getType())) || + fir::isa_char(fir::unwrapRefType(varPtr.getType()))) { + if (canPassByValue(fir::unwrapRefType(varPtr.getType()))) { + captureKind = mlir::omp::VariableCaptureKind::ByCopy; + } + } + return omp::MapInfoOp::create( builder, loc, varPtr.getType(), varPtr, TypeAttr::get(llvm::cast(varPtr.getType()) .getElementType()), builder.getIntegerAttr(builder.getIntegerType(64, /*isSigned=*/false), mapTypeTo), - builder.getAttr( - omp::VariableCaptureKind::ByRef), + builder.getAttr(captureKind), /*varPtrPtr=*/Value{}, /*members=*/SmallVector{}, /*member_index=*/mlir::ArrayAttr{}, diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 4c3e509b5a36d..394a9b9bc1de3 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -24,6 +24,7 @@ #include "flang/Semantics/openmp-modifiers.h" #include "flang/Semantics/symbol.h" #include "flang/Semantics/tools.h" +#include "flang/Support/Flags.h" #include "llvm/Frontend/OpenMP/OMP.h.inc" #include "llvm/Support/Debug.h" #include @@ -56,6 +57,10 @@ template class DirectiveAttributeVisitor { Scope &scope; Symbol::Flag defaultDSA{Symbol::Flag::AccShared}; // TODOACC std::map objectWithDSA; + std::map + defaultMap; + bool withinConstruct{false}; std::int64_t associatedLoopLevel{0}; }; @@ -80,6 +85,10 @@ template class DirectiveAttributeVisitor { GetContext().directiveSource = dir; } Scope &currScope() { return GetContext().scope; } + void AddContextDefaultmapBehaviour(parser::OmpVariableCategory::Value VarCat, + parser::OmpDefaultmapClause::ImplicitBehavior ImpBehav) { + GetContext().defaultMap[VarCat] = ImpBehav; + } void SetContextDefaultDSA(Symbol::Flag flag) { GetContext().defaultDSA = flag; } @@ -557,6 +566,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor { ResolveOmpObjectList(x.v, Symbol::Flag::OmpExclusiveScan); return false; } + void Post(const parser::OmpClause::Defaultmap &); void Post(const parser::OmpDefaultClause &); bool Pre(const parser::OmpClause::Shared &x) { ResolveOmpObjectList(x.v, Symbol::Flag::OmpShared); @@ -810,6 +820,11 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor { Symbol::Flag::OmpLastPrivate, Symbol::Flag::OmpReduction, Symbol::Flag::OmpLinear}; + Symbol::Flags dataMappingAttributeFlags{Symbol::Flag::OmpMapTo, + Symbol::Flag::OmpMapFrom, Symbol::Flag::OmpMapToFrom, + Symbol::Flag::OmpMapStorage, Symbol::Flag::OmpMapDelete, + Symbol::Flag::OmpIsDevicePtr, Symbol::Flag::OmpHasDeviceAddr}; + Symbol::Flags privateDataSharingAttributeFlags{Symbol::Flag::OmpPrivate, Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate}; @@ -2214,6 +2229,28 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPAllocatorsConstruct &x) { return true; } +void OmpAttributeVisitor::Post(const parser::OmpClause::Defaultmap &x) { + using ImplicitBehavior = parser::OmpDefaultmapClause::ImplicitBehavior; + using VariableCategory = parser::OmpVariableCategory; + + VariableCategory::Value varCategory; + ImplicitBehavior impBehavior; + + if (!dirContext_.empty()) { + impBehavior = std::get(x.v.t); + + auto &modifiers{OmpGetModifiers(x.v)}; + auto *maybeCategory{ + OmpGetUniqueModifier(modifiers)}; + if (maybeCategory) + varCategory = maybeCategory->v; + else + varCategory = VariableCategory::Value::All; + + AddContextDefaultmapBehaviour(varCategory, impBehavior); + } +} + void OmpAttributeVisitor::Post(const parser::OmpDefaultClause &x) { // The DEFAULT clause may also be used on METADIRECTIVE. In that case // there is nothing to do. @@ -2365,6 +2402,70 @@ static bool IsSymbolStaticStorageDuration(const Symbol &symbol) { (ultSym.flags().test(Symbol::Flag::InCommonBlock)); } +static bool IsTargetCaptureImplicitlyFirstprivatizeable(const Symbol &symbol, + const Symbol::Flags &dsa, const Symbol::Flags &dataSharingAttributeFlags, + const Symbol::Flags &dataMappingAttributeFlags, + std::map + defaultMap) { + // If a Defaultmap clause is present for the current target scope, and it has + // specified behaviour other than Firstprivate for scalars then we exit early, + // as it overrides the implicit Firstprivatization of scalars OpenMP rule. + if (!defaultMap.empty()) { + if (llvm::is_contained( + defaultMap, parser::OmpVariableCategory::Value::All) && + defaultMap[parser::OmpVariableCategory::Value::All] != + parser::OmpDefaultmapClause::ImplicitBehavior::Firstprivate) { + return false; + } + + if (llvm::is_contained( + defaultMap, parser::OmpVariableCategory::Value::Scalar) && + defaultMap[parser::OmpVariableCategory::Value::Scalar] != + parser::OmpDefaultmapClause::ImplicitBehavior::Firstprivate) { + return false; + } + } + + auto checkSymbol = [&](const Symbol &checkSym) { + // if we're associated with any other flags we skip implicit privitization + // for now. If we're an allocatable, pointer or declare target, we're not + // implicitly firstprivitizeable under OpenMP restrictions. + // TODO: Relax restriction as we progress privitization and further + // investigate the flags we can intermix with. + if (!(dsa & (dataSharingAttributeFlags | dataMappingAttributeFlags)) + .none() || + !checkSym.flags().none() || semantics::IsAssumedShape(checkSym) || + semantics::IsAllocatableOrPointer(checkSym)) { + return false; + } + + // It is default firstprivatizeable as far as the OpenMP specification is + // concerned if it is a non-array scalar type that has been implicitly + // captured in a target region + const auto *type{checkSym.GetType()}; + if ((!checkSym.GetShape() || checkSym.GetShape()->empty()) && + (type->category() == + Fortran::semantics::DeclTypeSpec::Category::Numeric || + type->category() == + Fortran::semantics::DeclTypeSpec::Category::Logical || + type->category() == + Fortran::semantics::DeclTypeSpec::Category::Character)) { + return true; + } + return false; + }; + + if (checkSymbol(symbol)) { + const auto *hostAssoc{symbol.detailsIf()}; + if (hostAssoc) { + return checkSymbol(hostAssoc->symbol()); + } + return true; + } + return false; +} + void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) { if (!IsPrivatizable(symbol)) { return; @@ -2456,7 +2557,7 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) { bool taskGenDir = llvm::omp::taskGeneratingSet.test(dirContext.directive); bool targetDir = llvm::omp::allTargetSet.test(dirContext.directive); - bool parallelDir = llvm::omp::allParallelSet.test(dirContext.directive); + bool parallelDir = llvm::omp::topParallelSet.test(dirContext.directive); bool teamsDir = llvm::omp::allTeamsSet.test(dirContext.directive); bool isStaticStorageDuration = IsSymbolStaticStorageDuration(*symbol); @@ -2512,8 +2613,19 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) { useLastDeclSymbol(); PRINT_IMPLICIT_RULE("3) enclosing context"); } else if (targetDir) { - // TODO 4) not mapped target variable -> firstprivate + // 4) not mapped target variable -> firstprivate + // - i.e. implicit, but meets OpenMP specification rules for + // firstprivate "promotion" + if (enableDelayedPrivatizationStaging && + IsTargetCaptureImplicitlyFirstprivatizeable(*symbol, prevDSA, + dataSharingAttributeFlags, dataMappingAttributeFlags, + dirContext.defaultMap)) { + prevDSA.set(Symbol::Flag::OmpImplicit); + prevDSA.set(Symbol::Flag::OmpFirstPrivate); + makeSymbol(prevDSA); + } dsa = prevDSA; + PRINT_IMPLICIT_RULE("4) not mapped target variable -> firstprivate"); } else if (taskGenDir) { // TODO 5) dummy arg in orphaned taskgen construct -> firstprivate if (prevDSA.test(Symbol::Flag::OmpShared) || diff --git a/flang/test/Integration/OpenMP/map-types-and-sizes.f90 b/flang/test/Integration/OpenMP/map-types-and-sizes.f90 index aa68c13558a7b..665be5a8db4d4 100644 --- a/flang/test/Integration/OpenMP/map-types-and-sizes.f90 +++ b/flang/test/Integration/OpenMP/map-types-and-sizes.f90 @@ -6,14 +6,17 @@ ! added to this directory and sub-directories. !===----------------------------------------------------------------------===! -!RUN: %flang_fc1 -emit-llvm -fopenmp -fopenmp-version=51 -fopenmp-targets=amdgcn-amd-amdhsa %s -o - | FileCheck %s +!RUN: %flang_fc1 -emit-llvm -fopenmp -mmlir --enable-delayed-privatization-staging=false -fopenmp-version=51 -fopenmp-targets=amdgcn-amd-amdhsa %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NO-FPRIV +!RUN: %flang_fc1 -emit-llvm -fopenmp -mmlir --enable-delayed-privatization-staging=true -fopenmp-version=51 -fopenmp-targets=amdgcn-amd-amdhsa %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-FPRIV + !=============================================================================== ! Check MapTypes for target implicit captures !=============================================================================== !CHECK: @.offload_sizes = private unnamed_addr constant [1 x i64] [i64 4] -!CHECK: @.offload_maptypes = private unnamed_addr constant [1 x i64] [i64 800] +!CHECK-FPRIV: @.offload_maptypes = private unnamed_addr constant [1 x i64] [i64 289] +!CHECK-NO-FPRIV: @.offload_maptypes = private unnamed_addr constant [1 x i64] [i64 800] subroutine mapType_scalar integer :: a !$omp target @@ -372,7 +375,8 @@ subroutine mapType_nested_derived_type_member_idx() end subroutine !CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [2 x i64] [i64 8, i64 4] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [2 x i64] [i64 544, i64 800] +!CHECK-FPRIV: @.offload_maptypes{{.*}} = private unnamed_addr constant [2 x i64] [i64 544, i64 289] +!CHECK-NO-FPRIV: @.offload_maptypes{{.*}} = private unnamed_addr constant [2 x i64] [i64 544, i64 800] subroutine mapType_c_ptr use iso_c_binding, only : c_ptr, c_loc type(c_ptr) :: a @@ -383,7 +387,8 @@ subroutine mapType_c_ptr end subroutine mapType_c_ptr !CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [1 x i64] [i64 1] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 800] +!CHECK-FPRIV: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 289] +!CHECK-NO-FPRIV: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 800] subroutine mapType_char character :: a !$omp target diff --git a/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-implicit-scalar-map.f90 b/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-implicit-scalar-map.f90 new file mode 100644 index 0000000000000..52a1f31cc3ce3 --- /dev/null +++ b/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-implicit-scalar-map.f90 @@ -0,0 +1,42 @@ +! Tests delayed privatization works for implicit capture of scalars similarly to +! the way it works for explicitly firstprivitized scalars. + +! RUN: %flang_fc1 -emit-mlir -fopenmp -mmlir --enable-delayed-privatization-staging \ +! RUN: -o - %s 2>&1 | FileCheck %s + +! CHECK-LABEL: omp.private {type = firstprivate} @_QFExdgfx_firstprivate_i32 : i32 copy { +! CHECK: ^bb0(%{{.*}}: !fir.ref, %{{.*}}: !fir.ref): +! CHECK: %{{.*}} = fir.load %{{.*}} : !fir.ref +! CHECK: fir.store %{{.*}} to %{{.*}} : !fir.ref +! CHECK: omp.yield(%{{.*}} : !fir.ref) +! CHECK: } + +! CHECK-LABEL: omp.private {type = firstprivate} @_QFExfpvx_firstprivate_i32 : i32 copy { +! CHECK: ^bb0(%{{.*}}: !fir.ref, %{{.*}}: !fir.ref): +! CHECK: %{{.*}} = fir.load %{{.*}} : !fir.ref +! CHECK: fir.store %{{.*}} to %{{.*}} : !fir.ref +! CHECK: omp.yield(%{{.*}} : !fir.ref) +! CHECK: } + +! CHECK: %[[VAL_0:.*]] = fir.alloca i32 {bindc_name = "xdgfx", uniq_name = "_QFExdgfx"} +! CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] {uniq_name = "_QFExdgfx"} : (!fir.ref) -> !fir.ref +! CHECK: %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "xfpvx", uniq_name = "_QFExfpvx"} +! CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_2]] {uniq_name = "_QFExfpvx"} : (!fir.ref) -> !fir.ref +! CHECK: %[[VAL_4:.*]] = omp.map.info var_ptr(%[[VAL_3]] : !fir.ref, i32) map_clauses(to) capture(ByCopy) -> !fir.ref +! CHECK: %[[VAL_5:.*]] = omp.map.info var_ptr(%[[VAL_1]] : !fir.ref, i32) map_clauses(to) capture(ByCopy) -> !fir.ref + +! CHECK: omp.target map_entries(%[[VAL_4]] -> %{{.*}}, %[[VAL_5]] -> %{{.*}} : !fir.ref, !fir.ref) private(@_QFExfpvx_firstprivate_i32 %[[VAL_3]] -> %[[VAL_6:.*]] [map_idx=0], @_QFExdgfx_firstprivate_i32 %[[VAL_1]] -> %[[VAL_7:.*]] [map_idx=1] : !fir.ref, !fir.ref) { +! CHECK: %{{.*}} = fir.declare %[[VAL_6]] {uniq_name = "_QFExfpvx"} : (!fir.ref) -> !fir.ref +! CHECK: %{{.*}} = fir.declare %[[VAL_7]] {uniq_name = "_QFExdgfx"} : (!fir.ref) -> !fir.ref + +program test_default_implicit_firstprivate + implicit none + integer :: xdgfx, xfpvx + xdgfx = 1 + xfpvx = 2 + !$omp target firstprivate(xfpvx) + xdgfx = 42 + xfpvx = 43 + !$omp end target + write(*,*) xdgfx, xfpvx +end program diff --git a/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-multiple-variables.f90 b/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-multiple-variables.f90 index 217ac5638a3ea..5144b33cf4fe1 100644 --- a/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-multiple-variables.f90 +++ b/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-multiple-variables.f90 @@ -36,6 +36,10 @@ end subroutine target_allocatable ! Test the privatizer for `character` ! +! CHECK: omp.private {type = firstprivate} +! CHECK-SAME: @[[FIRSTPRIVATE_SCALAR_SYM:[^[:space:]]+mapped_var[^[:space:]]+]] +! CHECK-SAME: : [[FIRSTPRIVATE_TYPE:i32]] copy { + ! CHECK: omp.private {type = private} ! CHECK-SAME: @[[CHAR_PRIVATIZER_SYM:[^[:space:]]+char_var[^[:space:]]+]] ! CHECK-SAME: : [[CHAR_TYPE:!fir.boxchar<1>]] init { @@ -77,6 +81,7 @@ end subroutine target_allocatable ! Test the privatizer for `real(:)`'s lower bound ! + ! CHECK: omp.private {type = private} ! CHECK-SAME: @[[LB_PRIVATIZER_SYM:[^[:space:]]+lb[^[:space:]]+]] ! CHECK-SAME: : [[LB_TYPE:i64]]{{$}} @@ -139,28 +144,29 @@ end subroutine target_allocatable ! CHECK: %[[REAL_ARR_ALLOC:.*]] = fir.alloca !fir.array, {{.*}} {bindc_name = "real_arr", {{.*}}} ! CHECK: %[[REAL_ARR_DECL:.*]]:2 = hlfir.declare %[[REAL_ARR_ALLOC]]({{.*}}) ! CHECK: fir.store %[[REAL_ARR_DECL]]#0 to %[[REAL_ARR_DESC_ALLOCA]] : !fir.ref>> -! CHECK: %[[MAPPED_MI0:.*]] = omp.map.info var_ptr(%[[MAPPED_DECL]]#1 : !fir.ref, i32) {{.*}} ! CHECK: %[[ALLOC_VAR_MEMBER:.*]] = omp.map.info var_ptr(%[[ALLOC_VAR_DECL]]#0 : !fir.ref>>, i32) ! CHECK: %[[ALLOC_VAR_MAP:.*]] = omp.map.info var_ptr(%[[ALLOC_VAR_DECL]]#0 : !fir.ref>>, !fir.box>) {{.*}} members(%[[ALLOC_VAR_MEMBER]] : ! CHECK: %[[REAL_ARR_MEMBER:.*]] = omp.map.info var_ptr(%[[REAL_ARR_DESC_ALLOCA]] : !fir.ref>>, f32) ! CHECK: %[[REAL_ARR_DESC_MAP:.*]] = omp.map.info var_ptr(%[[REAL_ARR_DESC_ALLOCA]] : !fir.ref>>, !fir.box>) {{.*}} members(%[[REAL_ARR_MEMBER]] : ! CHECK: fir.store %[[CHAR_VAR_DECL]]#0 to %[[CHAR_VAR_DESC_ALLOCA]] : !fir.ref> ! CHECK: %[[CHAR_VAR_DESC_MAP:.*]] = omp.map.info var_ptr(%[[CHAR_VAR_DESC_ALLOCA]] : !fir.ref>, !fir.boxchar<1>) +! CHECK: %[[MAPPED_MI0:.*]] = omp.map.info var_ptr(%[[MAPPED_DECL]]#0 : !fir.ref, i32) {{.*}} ! CHECK: omp.target ! CHECK-SAME: map_entries( -! CHECK-SAME: %[[MAPPED_MI0]] -> %[[MAPPED_ARG0:[^,]+]], ! CHECK-SAME: %[[ALLOC_VAR_MAP]] -> %[[MAPPED_ARG1:[^,]+]] ! CHECK-SAME: %[[REAL_ARR_DESC_MAP]] -> %[[MAPPED_ARG2:[^,]+]] ! CHECK-SAME: %[[CHAR_VAR_DESC_MAP]] -> %[[MAPPED_ARG3:.[^,]+]] -! CHECK-SAME: !fir.ref, !fir.ref>>, !fir.ref>>, !fir.ref>, !fir.llvm_ptr>, !fir.llvm_ptr>> +! CHECK-SAME: %[[MAPPED_MI0]] -> %[[MAPPED_ARG0:[^,]+]] +! CHECK-SAME: !fir.ref>>, !fir.ref>>, !fir.ref>, !fir.ref, !fir.llvm_ptr>, !fir.llvm_ptr>>, !fir.ref> ! CHECK-SAME: private( -! CHECK-SAME: @[[ALLOC_PRIVATIZER_SYM]] %{{[^[:space:]]+}}#0 -> %[[ALLOC_ARG:[^,]+]] [map_idx=1], +! CHECK-SAME: @[[ALLOC_PRIVATIZER_SYM]] %{{[^[:space:]]+}}#0 -> %[[ALLOC_ARG:[^,]+]] [map_idx=0], ! CHECK-SAME: @[[REAL_PRIVATIZER_SYM]] %{{[^[:space:]]+}}#0 -> %[[REAL_ARG:[^,]+]], ! CHECK-SAME: @[[LB_PRIVATIZER_SYM]] %{{[^[:space:]]+}}#0 -> %[[LB_ARG:[^,]+]], -! CHECK-SAME: @[[ARR_PRIVATIZER_SYM]] %{{[^[:space:]]+}} -> %[[ARR_ARG:[^,]+]] [map_idx=2], +! CHECK-SAME: @[[ARR_PRIVATIZER_SYM]] %{{[^[:space:]]+}} -> %[[ARR_ARG:[^,]+]] [map_idx=1], ! CHECK-SAME: @[[COMP_PRIVATIZER_SYM]] %{{[^[:space:]]+}}#0 -> %[[COMP_ARG:[^,]+]], -! CHECK-SAME: @[[CHAR_PRIVATIZER_SYM]] %{{[^[:space:]]+}}#0 -> %[[CHAR_ARG:[^,]+]] [map_idx=3] : -! CHECK-SAME: !fir.ref>>, !fir.ref, !fir.ref, !fir.ref>>, !fir.ref>, !fir.boxchar<1>) { +! CHECK-SAME: @[[CHAR_PRIVATIZER_SYM]] %{{[^[:space:]]+}}#0 -> %[[CHAR_ARG:[^,]+]] [map_idx=2] +! CHECK-SAME: @[[FIRSTPRIVATE_SCALAR_SYM]] %{{[^[:space:]]+}}#0 -> %[[FP_SCALAR_ARG:[^,]+]] [map_idx=3] : +! CHECK-SAME: !fir.ref>>, !fir.ref, !fir.ref, !fir.ref>>, !fir.ref>, !fir.boxchar<1>, !fir.ref) ! CHECK-NOT: fir.alloca ! CHECK: hlfir.declare %[[ALLOC_ARG]] ! CHECK: hlfir.declare %[[REAL_ARG]] diff --git a/flang/test/Lower/OpenMP/DelayedPrivatization/target-teams-private-implicit-scalar-map.f90 b/flang/test/Lower/OpenMP/DelayedPrivatization/target-teams-private-implicit-scalar-map.f90 new file mode 100644 index 0000000000000..39f9738932d44 --- /dev/null +++ b/flang/test/Lower/OpenMP/DelayedPrivatization/target-teams-private-implicit-scalar-map.f90 @@ -0,0 +1,45 @@ +! Tests delayed privatization works for implicit capture of scalars similarly to +! the way it works for explicitly firstprivitized scalars. + +! RUN: %flang_fc1 -emit-mlir -fopenmp -mmlir --enable-delayed-privatization-staging \ +! RUN: -o - %s 2>&1 | FileCheck %s + +!CHECK: omp.private {type = private} @[[SYM_K:.*]] : i32 +!CHECK: omp.private {type = private} @[[SYM_J:.*]] : i32 +!CHECK: omp.private {type = private} @[[SYM_I:.*]] : i32 +!CHECK: omp.private {type = firstprivate} @[[SYM_XDGFX:.*]] : i32 copy { +!CHECK: omp.private {type = firstprivate} @[[SYM_XFPVX:.*]] : i32 copy { + +program test_default_implicit_firstprivate + implicit none + integer :: xdgfx, xfpvx + integer :: i,j,k + integer :: arr(10,10,10) + integer, allocatable :: allocarr(:,:,:) +!CHECK: %[[VAL_0:.*]] = fir.declare %{{.*}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFEallocarr"} : (!fir.ref>>>) -> !fir.ref>>> +!CHECK: %[[VAL_1:.*]] = fir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFEarr"} : (!fir.ref>, !fir.shape<3>) -> !fir.ref> +!CHECK: %[[VAL_2:.*]] = fir.declare %{{.*}} {uniq_name = "_QFEi"} : (!fir.ref) -> !fir.ref +!CHECK: %[[VAL_3:.*]] = fir.declare %{{.*}} {uniq_name = "_QFEj"} : (!fir.ref) -> !fir.ref +!CHECK: %[[VAL_4:.*]] = fir.declare %{{.*}} {uniq_name = "_QFEk"} : (!fir.ref) -> !fir.ref +!CHECK: %[[VAL_5:.*]] = fir.declare %{{.*}} {uniq_name = "_QFExdgfx"} : (!fir.ref) -> !fir.ref +!CHECK: %[[VAL_6:.*]] = fir.declare %{{.*}} {uniq_name = "_QFExfpvx"} : (!fir.ref) -> !fir.ref +!CHECK: %[[VAL_7:.*]] = omp.map.info var_ptr(%[[VAL_2]] : !fir.ref, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref {name = "i"} +!CHECK: %[[VAL_8:.*]] = omp.map.info var_ptr(%[[VAL_3]] : !fir.ref, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref {name = "j"} +!CHECK: %[[VAL_9:.*]] = omp.map.info var_ptr(%[[VAL_4]] : !fir.ref, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref {name = "k"} +!CHECK: %[[VAL_10:.*]] = fir.box_offset %[[VAL_0]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> +!CHECK: %[[VAL_11:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>>>, i32) map_clauses(implicit, tofrom) capture(ByRef) var_ptr_ptr(%[[VAL_10]] : !fir.llvm_ptr>>) bounds({{.*}}) -> !fir.llvm_ptr>> {name = ""} +!CHECK: %[[VAL_12:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>>>, !fir.box>>) map_clauses(implicit, to) capture(ByRef) members(%[[VAL_11]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "allocarr"} +!CHECK: %[[VAL_13:.*]] = omp.map.info var_ptr(%[[VAL_1]] : !fir.ref>, !fir.array<10x10x10xi32>) map_clauses(implicit, tofrom) capture(ByRef) bounds({{.*}}) -> !fir.ref> {name = "arr"} +!CHECK: %[[VAL_14:.*]] = omp.map.info var_ptr(%[[VAL_6]] : !fir.ref, i32) map_clauses(to) capture(ByCopy) -> !fir.ref +!CHECK: %[[VAL_15:.*]] = omp.map.info var_ptr(%[[VAL_5]] : !fir.ref, i32) map_clauses(to) capture(ByCopy) -> !fir.ref +!CHECK: omp.target host_eval({{.*}}) map_entries(%[[VAL_7]] -> %{{.*}}, %[[VAL_8]] -> %{{.*}}, %[[VAL_9]] -> %{{.*}}, %[[VAL_12]] -> %{{.*}}, %[[VAL_13]] -> %{{.*}}, %[[VAL_14]] -> %{{.*}}, %[[VAL_15]] -> %{{.*}}, %[[VAL_11]] -> %{{.*}} : {{.*}}) private(@[[SYM_XFPVX]] %[[VAL_6]] -> %{{.*}} [map_idx=5], @[[SYM_XDGFX]] %[[VAL_5]] -> %{{.*}} [map_idx=6] : {{.*}}) { +!CHECK omp.parallel private(@[[SYM_XFPVX]] %{{.*}} -> %{{.*}}, @[[SYM_XDGFX]] %{{.*}} -> %{{.*}}, @[[SYM_I]] %{{.*}} -> %{{.*}}, @[[SYM_J]] %{{.*}} -> %{{.*}}, @[[SYM_K]] %{{.*}} -> %{{.*}} : {{.*}}) { + !$omp target teams distribute parallel do collapse(3) firstprivate(xfpvx) + do i = 1, 10 + do j = 1, 10 + do k = 1, 10 + allocarr(i,j,k) = arr(i,j,k) + xdgfx + xfpvx + end do + end do + end do +end program diff --git a/flang/test/Lower/OpenMP/Todo/defaultmap-clause-firstprivate.f90 b/flang/test/Lower/OpenMP/Todo/defaultmap-clause-firstprivate.f90 index 0af2c7f5ea818..6818c39f63a3c 100644 --- a/flang/test/Lower/OpenMP/Todo/defaultmap-clause-firstprivate.f90 +++ b/flang/test/Lower/OpenMP/Todo/defaultmap-clause-firstprivate.f90 @@ -3,7 +3,9 @@ subroutine f00 implicit none - integer :: i + ! NOTE: This is implemented for scalars as it is the default behaviour, so we utilise + ! a different data type. + integer, allocatable :: i !CHECK: not yet implemented: Firstprivate and None are currently unsupported defaultmap behaviour !$omp target defaultmap(firstprivate) i = 10 diff --git a/flang/test/Lower/OpenMP/defaultmap.f90 b/flang/test/Lower/OpenMP/defaultmap.f90 index 89d86ac1b8cc9..0b26f5db0feb3 100644 --- a/flang/test/Lower/OpenMP/defaultmap.f90 +++ b/flang/test/Lower/OpenMP/defaultmap.f90 @@ -1,4 +1,5 @@ -!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 %s -o - | FileCheck %s +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -mmlir --enable-delayed-privatization-staging=false %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NO-FPRIV +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -mmlir --enable-delayed-privatization-staging=true %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-FPRIV subroutine defaultmap_allocatable_present() implicit none @@ -49,9 +50,11 @@ subroutine defaultmap_pointer_to() integer, dimension(:), pointer :: arr_ptr(:) integer :: scalar_int -! CHECK: %[[MAP_1:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, i32) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr({{.*}}) bounds({{.*}}) -> !fir.llvm_ptr>> {name = ""} +! CHECK-NO-FPRIV: %[[MAP_1:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, i32) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr({{.*}}) bounds({{.*}}) -> !fir.llvm_ptr>> {name = ""} +! CHECK-FPRIV: %[[MAP_1:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, i32) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr({{.*}}) bounds({{.*}}) -> !fir.llvm_ptr>> {name = ""} ! CHECK: %[[MAP_2:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(implicit, to) capture(ByRef) members({{.*}}) -> !fir.ref>>> {name = "arr_ptr"} -! CHECK: %[[MAP_3:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref {name = "scalar_int"} +! CHECK-FPRIV: %[[MAP_3:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref, i32) map_clauses(to) capture(ByCopy) -> !fir.ref +! CHECK-NO-FPRIV: %[[MAP_3:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref {name = "scalar_int"} !$omp target defaultmap(to: pointer) arr_ptr(1) = scalar_int + 20 !$omp end target diff --git a/flang/test/Lower/OpenMP/optional-argument-map-2.f90 b/flang/test/Lower/OpenMP/optional-argument-map-2.f90 index e713d71cfbec9..a7744074d3c68 100644 --- a/flang/test/Lower/OpenMP/optional-argument-map-2.f90 +++ b/flang/test/Lower/OpenMP/optional-argument-map-2.f90 @@ -1,4 +1,5 @@ -!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s +!RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --enable-delayed-privatization-staging=false %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NO-FPRIV +!RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --enable-delayed-privatization-staging=true %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-FPRIV module mod implicit none @@ -52,7 +53,6 @@ end module mod ! CHECK: fir.store %[[VAL_24]] to %[[VAL_0]] : !fir.ref>>> ! CHECK: } - ! CHECK-LABEL: func.func @_QMmodProutine_boxchar( ! CHECK-SAME: %[[ARG0:.*]]: !fir.boxchar<1> {fir.bindc_name = "a", fir.optional}) { ! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.boxchar<1> @@ -63,33 +63,55 @@ end module mod ! CHECK: %[[VAL_5:.*]] = fir.alloca !fir.char<1,4> {bindc_name = "b", uniq_name = "_QMmodFroutine_boxcharEb"} ! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[VAL_4]] {uniq_name = "_QMmodFroutine_boxcharEb"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_7:.*]] = omp.map.info var_ptr(%[[VAL_6]]#1 : !fir.ref>, !fir.char<1,4>) map_clauses(from) capture(ByRef) -> !fir.ref> {name = "b"} -! CHECK: %[[VAL_8:.*]] = fir.is_present %[[VAL_3]]#1 : (!fir.ref>) -> i1 -! CHECK: %[[VAL_9:.*]] = arith.constant 0 : index -! CHECK: %[[VAL_10:.*]] = arith.constant 1 : index -! CHECK: %[[VAL_11:.*]]:2 = fir.if %[[VAL_8]] -> (index, index) { -! CHECK: %[[VAL_12:.*]]:2 = fir.unboxchar %[[VAL_3]]#0 : (!fir.boxchar<1>) -> (!fir.ref>, index) -! CHECK: fir.result %[[VAL_12]]#1, %[[VAL_10]] : index, index -! CHECK: } else { -! CHECK: fir.result %[[VAL_9]], %[[VAL_9]] : index, index -! CHECK: } -! CHECK: %[[VAL_13:.*]] = arith.subi %[[VAL_14:.*]]#0, %[[VAL_10]] : index -! CHECK: %[[VAL_15:.*]] = omp.map.bounds lower_bound(%[[VAL_9]] : index) upper_bound(%[[VAL_13]] : index) extent(%[[VAL_14]]#0 : index) stride(%[[VAL_14]]#1 : index) start_idx(%[[VAL_9]] : index) {stride_in_bytes = true} -! CHECK: %[[VAL_16:.*]] = omp.map.info var_ptr(%[[VAL_3]]#1 : !fir.ref>, !fir.char<1,?>) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) bounds(%[[VAL_15]]) -> !fir.ref> {name = "a"} -! CHECK: fir.store %[[ARG0]] to %[[VAL_0]] : !fir.ref> -! CHECK: %[[VAL_17:.*]] = arith.constant 0 : index -! CHECK: %[[VAL_18:.*]] = arith.constant 1 : index -! CHECK: %[[VAL_19:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref>, index) -! CHECK: %[[VAL_20:.*]] = arith.subi %[[VAL_19]]#1, %[[VAL_18]] : index -! CHECK: %[[VAL_21:.*]] = omp.map.bounds lower_bound(%[[VAL_17]] : index) upper_bound(%[[VAL_20]] : index) extent(%[[VAL_19]]#1 : index) stride(%[[VAL_18]] : index) start_idx(%[[VAL_17]] : index) {stride_in_bytes = true} -! CHECK: %[[VAL_22:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.boxchar<1>) map_clauses(implicit, to) capture(ByRef) bounds(%[[VAL_21]]) -> !fir.ref> {name = ""} -! CHECK: omp.target map_entries(%[[VAL_7]] -> %[[VAL_23:.*]], %[[VAL_16]] -> %[[VAL_24:.*]], %[[VAL_22]] -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { -! CHECK: %[[VAL_26:.*]] = fir.load %[[VAL_25]] : !fir.ref> -! CHECK: %[[VAL_27:.*]]:2 = fir.unboxchar %[[VAL_26]] : (!fir.boxchar<1>) -> (!fir.ref>, index) -! CHECK: %[[VAL_28:.*]] = arith.constant 4 : index -! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_23]] typeparams %[[VAL_28]] {uniq_name = "_QMmodFroutine_boxcharEb"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) -! CHECK: %[[VAL_30:.*]]:2 = hlfir.declare %[[VAL_24]] typeparams %[[VAL_27]]#1 {fortran_attrs = #fir.var_attrs, uniq_name = "_QMmodFroutine_boxcharEa"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) -! CHECK: hlfir.assign %[[VAL_30]]#0 to %[[VAL_29]]#0 : !fir.boxchar<1>, !fir.ref> -! CHECK: omp.terminator -! CHECK: } -! CHECK: return -! CHECK: } +! CHECK-FPRIV: fir.store %[[VAL_3]]#0 to %[[VAL_0]] : !fir.ref> +! CHECK-FPRIV: %[[VAL_8:.*]] = fir.load %[[VAL_0]] : !fir.ref> +! CHECK-FPRIV: %[[VAL_9:.*]]:2 = fir.unboxchar %[[VAL_8]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-FPRIV: %[[VAL_10:.*]] = arith.constant 0 : index +! CHECK-FPRIV: %[[VAL_11:.*]] = arith.constant 1 : index +! CHECK-FPRIV: %[[VAL_12:.*]]:2 = fir.unboxchar %[[VAL_8]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-FPRIV: %[[VAL_13:.*]] = arith.subi %[[VAL_12]]#1, %[[VAL_11]] : index +! CHECK-FPRIV: %[[VAL_14:.*]] = omp.map.bounds lower_bound(%[[VAL_10]] : index) upper_bound(%[[VAL_13]] : index) extent(%[[VAL_12]]#1 : index) stride(%[[VAL_11]] : index) start_idx(%[[VAL_10]] : index) {stride_in_bytes = true} +! CHECK-FPRIV: %[[VAL_15:.*]] = fir.load %[[VAL_0]] : !fir.ref> +! CHECK-FPRIV: %[[VAL_16:.*]] = fir.box_offset %[[VAL_0]] base_addr : (!fir.ref>) -> !fir.llvm_ptr>> +! CHECK-FPRIV: %[[VAL_17:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.char<1,?>) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr(%[[VAL_16]] : !fir.llvm_ptr>>) bounds(%[[VAL_14]]) -> !fir.ref> +! CHECK-FPRIV: %[[VAL_18:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.boxchar<1>) map_clauses(to) capture(ByRef) members(%[[VAL_17]] : [0] : !fir.ref>) -> !fir.ref> +! CHECK-FPRIV: omp.target map_entries(%[[VAL_7]] -> %[[VAL_19:.*]], %[[VAL_18]] -> %[[VAL_20:.*]], %[[VAL_17]] -> %[[VAL_21:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) private(@_QMmodFroutine_boxcharEa_firstprivate_boxchar_c8xU %[[VAL_3]]#0 -> %[[VAL_22:.*]] [map_idx=1] : !fir.boxchar<1>) { +! CHECK-FPRIV: %[[VAL_23:.*]] = arith.constant 4 : index +! CHECK-FPRIV: %[[VAL_24:.*]]:2 = hlfir.declare %[[VAL_19]] typeparams %[[VAL_23]] {uniq_name = "_QMmodFroutine_boxcharEb"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK-FPRIV: %[[VAL_25:.*]]:2 = fir.unboxchar %[[VAL_22]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-FPRIV: %[[VAL_26:.*]]:2 = hlfir.declare %[[VAL_25]]#0 typeparams %[[VAL_25]]#1 {fortran_attrs = #fir.var_attrs, uniq_name = "_QMmodFroutine_boxcharEa"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) +! CHECK-FPRIV: hlfir.assign %[[VAL_26]]#0 to %[[VAL_24]]#0 : !fir.boxchar<1>, !fir.ref> +! CHECK-FPRIV: omp.terminator +! CHECK-FPRIV: } +! CHECK-FPRIV: return +! CHECK-FPRIV: } +! CHECK-NO-FPRIV: %[[VAL_8:.*]] = fir.is_present %[[VAL_3]]#1 : (!fir.ref>) -> i1 +! CHECK-NO-FPRIV: %[[VAL_9:.*]] = arith.constant 0 : index +! CHECK-NO-FPRIV: %[[VAL_10:.*]] = arith.constant 1 : index +! CHECK-NO-FPRIV: %[[VAL_11:.*]]:2 = fir.if %[[VAL_8]] -> (index, index) { +! CHECK-NO-FPRIV: %[[VAL_12:.*]]:2 = fir.unboxchar %[[VAL_3]]#0 : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-NO-FPRIV: fir.result %[[VAL_12]]#1, %[[VAL_10]] : index, index +! CHECK-NO-FPRIV: } else { +! CHECK-NO-FPRIV: fir.result %[[VAL_9]], %[[VAL_9]] : index, index +! CHECK-NO-FPRIV: } +! CHECK-NO-FPRIV: %[[VAL_13:.*]] = arith.subi %[[VAL_14:.*]]#0, %[[VAL_10]] : index +! CHECK-NO-FPRIV: %[[VAL_15:.*]] = omp.map.bounds lower_bound(%[[VAL_9]] : index) upper_bound(%[[VAL_13]] : index) extent(%[[VAL_14]]#0 : index) stride(%[[VAL_14]]#1 : index) start_idx(%[[VAL_9]] : index) {stride_in_bytes = true} +! CHECK-NO-FPRIV: %[[VAL_16:.*]] = omp.map.info var_ptr(%[[VAL_3]]#1 : !fir.ref>, !fir.char<1,?>) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) bounds(%[[VAL_15]]) -> !fir.ref> {name = "a"} +! CHECK-NO-FPRIV: fir.store %[[ARG0]] to %[[VAL_0]] : !fir.ref> +! CHECK-NO-FPRIV: %[[VAL_17:.*]] = arith.constant 0 : index +! CHECK-NO-FPRIV: %[[VAL_18:.*]] = arith.constant 1 : index +! CHECK-NO-FPRIV: %[[VAL_19:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-NO-FPRIV: %[[VAL_20:.*]] = arith.subi %[[VAL_19]]#1, %[[VAL_18]] : index +! CHECK-NO-FPRIV: %[[VAL_21:.*]] = omp.map.bounds lower_bound(%[[VAL_17]] : index) upper_bound(%[[VAL_20]] : index) extent(%[[VAL_19]]#1 : index) stride(%[[VAL_18]] : index) start_idx(%[[VAL_17]] : index) {stride_in_bytes = true} +! CHECK-NO-FPRIV: %[[VAL_22:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.boxchar<1>) map_clauses(implicit, to) capture(ByRef) bounds(%[[VAL_21]]) -> !fir.ref> {name = ""} +! CHECK-NO-FPRIV: omp.target map_entries(%[[VAL_7]] -> %[[VAL_23:.*]], %[[VAL_16]] -> %[[VAL_24:.*]], %[[VAL_22]] -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { +! CHECK-NO-FPRIV: %[[VAL_26:.*]] = fir.load %[[VAL_25]] : !fir.ref> +! CHECK-NO-FPRIV: %[[VAL_27:.*]]:2 = fir.unboxchar %[[VAL_26]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-NO-FPRIV: %[[VAL_28:.*]] = arith.constant 4 : index +! CHECK-NO-FPRIV: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_23]] typeparams %[[VAL_28]] {uniq_name = "_QMmodFroutine_boxcharEb"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK-NO-FPRIV: %[[VAL_30:.*]]:2 = hlfir.declare %[[VAL_24]] typeparams %[[VAL_27]]#1 {fortran_attrs = #fir.var_attrs, uniq_name = "_QMmodFroutine_boxcharEa"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) +! CHECK-NO-FPRIV: hlfir.assign %[[VAL_30]]#0 to %[[VAL_29]]#0 : !fir.boxchar<1>, !fir.ref> +! CHECK-NO-FPRIV: omp.terminator +! CHECK-NO-FPRIV: } +! CHECK-NO-FPRIV: return +! CHECK-NO-FPRIV: } diff --git a/flang/test/Lower/OpenMP/target-map-complex.f90 b/flang/test/Lower/OpenMP/target-map-complex.f90 index c15a10e4804dd..fc01bdafe51ed 100644 --- a/flang/test/Lower/OpenMP/target-map-complex.f90 +++ b/flang/test/Lower/OpenMP/target-map-complex.f90 @@ -1,14 +1,21 @@ -!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s +!RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --enable-delayed-privatization-staging=false %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NO-FPRIV +!RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --enable-delayed-privatization-staging=true %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-FPRIV ! Check that the complex*4 is passed by value. but complex*8 is passed by ! reference +!CHECK-FPRIV: omp.private {type = firstprivate} @[[PRIV_64:.*]] : complex copy { +!CHECK-FPRIV: omp.private {type = firstprivate} @[[PRIV_32:.*]] : complex copy { + !CHECK-LABEL: func.func @_QMmPbar() !CHECK: %[[V0:[0-9]+]]:2 = hlfir.declare {{.*}} (!fir.ref>) -> (!fir.ref>, !fir.ref>) !CHECK: %[[V1:[0-9]+]]:2 = hlfir.declare {{.*}} (!fir.ref>) -> (!fir.ref>, !fir.ref>) -!CHECK: %[[V2:[0-9]+]] = omp.map.info var_ptr(%[[V1]]#1 : !fir.ref>, complex) {{.*}} capture(ByCopy) -!CHECK: %[[V3:[0-9]+]] = omp.map.info var_ptr(%[[V0]]#1 : !fir.ref>, complex) {{.*}} capture(ByRef) -!CHECK: omp.target map_entries(%[[V2]] -> {{.*}}, %[[V3]] -> {{.*}} : !fir.ref>, !fir.ref>) +!CHECK-FPRIV: %[[V2:[0-9]+]] = omp.map.info var_ptr(%[[V1]]#0 : !fir.ref>, complex) {{.*}} capture(ByCopy) +!CHECK-FPRIV: %[[V3:[0-9]+]] = omp.map.info var_ptr(%[[V0]]#0 : !fir.ref>, complex) {{.*}} capture(ByRef) +!CHECK-FPRIV: omp.target map_entries(%[[V2]] -> {{.*}}, %[[V3]] -> {{.*}} : !fir.ref>, !fir.ref>) private(@[[PRIV_32]] %[[V1]]#0 -> %{{.*}} [map_idx=0], @[[PRIV_64]] %[[V0]]#0 -> %{{.*}} [map_idx=1] : !fir.ref>, !fir.ref>) { +!CHECK-NO-FPRIV: %[[V2:[0-9]+]] = omp.map.info var_ptr(%[[V1]]#1 : !fir.ref>, complex) {{.*}} capture(ByCopy) +!CHECK-NO-FPRIV: %[[V3:[0-9]+]] = omp.map.info var_ptr(%[[V0]]#1 : !fir.ref>, complex) {{.*}} capture(ByRef) +!CHECK-NO-PRIV: omp.target map_entries(%[[V2]] -> {{.*}}, %[[V3]] -> {{.*}} : !fir.ref>, !fir.ref>) module m implicit none @@ -25,6 +32,7 @@ subroutine foo(x, y) contains subroutine bar() + implicit none !$omp target call foo(cfval, cdval) !$omp end target diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90 index f04aacc63fc2b..1aef64a3b83a8 100644 --- a/flang/test/Lower/OpenMP/target.f90 +++ b/flang/test/Lower/OpenMP/target.f90 @@ -1,5 +1,6 @@ ! The "thread_limit" clause was added to the "target" construct in OpenMP 5.1. -! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 %s -o - | FileCheck %s +!RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --enable-delayed-privatization-staging=false -fopenmp-version=51 %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NO-FPRIV +!RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --enable-delayed-privatization-staging=true -fopenmp-version=51 %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-FPRIV !=============================================================================== ! Target_Enter Simple @@ -432,10 +433,15 @@ end subroutine omp_target_implicit !CHECK-LABEL: func.func @_QPomp_target_implicit_nested() { subroutine omp_target_implicit_nested integer::a, b - !CHECK: omp.target map_entries(%{{.*}} -> %[[ARG0:.*]], %{{.*}} -> %[[ARG1:.*]] : !fir.ref, !fir.ref) { + + !CHECK-NO-FPRIV: omp.target map_entries(%{{.*}} -> %[[ARG0:.*]], %{{.*}} -> %[[ARG1:.*]] : !fir.ref, !fir.ref) { + !CHECK-FPRIV: omp.target map_entries(%{{.*}} -> %[[ARG0:.*]], %{{.*}} -> %[[ARG1:.*]] : !fir.ref, !fir.ref) private(@{{.*}} %{{.*}} -> %[[ARG2:.*]] [map_idx=0], @{{.*}} %{{.*}} -> %[[ARG3:.*]] [map_idx=1] : !fir.ref, !fir.ref) { !$omp target - !CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[ARG0]] {uniq_name = "_QFomp_target_implicit_nestedEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) - !CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFomp_target_implicit_nestedEb"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK-NO-FPRIV: %[[VAL_8:.*]]:2 = hlfir.declare %[[ARG0]] {uniq_name = "_QFomp_target_implicit_nestedEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK-NO-FPRIV: %[[VAL_9:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFomp_target_implicit_nestedEb"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK-FPRIV: %[[VAL_8:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFomp_target_implicit_nestedEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK-FPRIV: %[[VAL_9:.*]]:2 = hlfir.declare %[[ARG3]] {uniq_name = "_QFomp_target_implicit_nestedEb"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK: %[[VAL_10:.*]] = arith.constant 10 : i32 !CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_8]]#0 : i32, !fir.ref a = 10 @@ -636,12 +642,18 @@ subroutine target_unstructured integer :: i = 1 !CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFtarget_unstructuredEj"} : (!fir.ref) -> (!fir.ref, !fir.ref) integer :: j = 11 - !CHECK: %[[VAL_4:.*]] = omp.map.info var_ptr(%[[VAL_1]]#1 : !fir.ref, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref {name = "i"} - !CHECK: %[[VAL_5:.*]] = omp.map.info var_ptr(%[[VAL_3]]#1 : !fir.ref, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref {name = "j"} - !CHECK: omp.target map_entries(%[[VAL_4]] -> %[[VAL_6:.*]], %[[VAL_5]] -> %[[VAL_7:.*]] : !fir.ref, !fir.ref) { + !CHECK-NO-FPRIV: %[[VAL_4:.*]] = omp.map.info var_ptr(%[[VAL_1]]#1 : !fir.ref, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref {name = "i"} + !CHECK-NO-FPRIV: %[[VAL_5:.*]] = omp.map.info var_ptr(%[[VAL_3]]#1 : !fir.ref, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref {name = "j"} + !CHECK-NO-FPRIV: omp.target map_entries(%[[VAL_4]] -> %[[VAL_6:.*]], %[[VAL_5]] -> %[[VAL_7:.*]] : !fir.ref, !fir.ref) { + !CHECK-FPRIV: %[[VAL_4:.*]] = omp.map.info var_ptr(%[[VAL_1]]#0 : !fir.ref, i32) map_clauses(to) capture(ByCopy) -> !fir.ref + !CHECK-FPRIV: %[[VAL_5:.*]] = omp.map.info var_ptr(%[[VAL_3]]#0 : !fir.ref, i32) map_clauses(to) capture(ByCopy) -> !fir.ref + !CHECK-FPRIV: omp.target map_entries(%[[VAL_4]] -> %[[ARG_0:.*]], %[[VAL_5]] -> %[[ARG_1:.*]] : !fir.ref, !fir.ref) private(@{{.*}} %[[VAL_1]]#0 -> %[[ARG_2:.*]] [map_idx=0], @{{.*}} %[[VAL_3]]#0 -> %[[ARG_3:.*]] [map_idx=1] : !fir.ref, !fir.ref) { !$omp target - !CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_6]] {uniq_name = "_QFtarget_unstructuredEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) - !CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFtarget_unstructuredEj"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK-FPRIV: %[[VAL_8:.*]]:2 = hlfir.declare %[[ARG_2]] {uniq_name = "_QFtarget_unstructuredEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK-FPRIV: %[[VAL_9:.*]]:2 = hlfir.declare %[[ARG_3]] {uniq_name = "_QFtarget_unstructuredEj"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK-NO-FPRIV: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_6]] {uniq_name = "_QFtarget_unstructuredEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK-NO-FPRIV: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFtarget_unstructuredEj"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK: ^bb1: do while (i <= j) !CHECK: ^bb2: