- Notifications
You must be signed in to change notification settings - Fork 15.3k
[Flang][OpenMP] Update declare mapper lookup via use-module #163860
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| @llvm/pr-subscribers-flang-parser @llvm/pr-subscribers-flang-fir-hlfir Author: Akash Banerjee (TIFitis) Changes
Fixes #163385. Full diff: https://github.com/llvm/llvm-project/pull/163860.diff 5 Files Affected:
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index 85398be778382..41820c74e3921 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -1402,10 +1402,14 @@ bool ClauseProcessor::processMap( } if (mappers) { assert(mappers->size() == 1 && "more than one mapper"); - mapperIdName = mappers->front().v.id().symbol->name().ToString(); - if (mapperIdName != "default") - mapperIdName = converter.mangleName( - mapperIdName, mappers->front().v.id().symbol->owner()); + const semantics::Symbol *mapperSym = mappers->front().v.id().symbol; + mapperIdName = mapperSym->name().ToString(); + if (mapperIdName != "default") { + // Mangle with the ultimate owner so that use-associated mapper + // identifiers resolve to the same symbol as their defining scope. + const semantics::Symbol &ultimate = mapperSym->GetUltimate(); + mapperIdName = converter.mangleName(mapperIdName, ultimate.owner()); + } } processMapObjects(stmtCtx, clauseLocation, diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index ae0ff9ca8068d..ef45c692acc8c 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1824,21 +1824,24 @@ bool OmpVisitor::Pre(const parser::OmpMapClause &x) { // TODO: Do we need a specific flag or type here, to distinghuish against // other ConstructName things? Leaving this for the full implementation // of mapper lowering. - auto *misc{symbol->detailsIf<MiscDetails>()}; + const Symbol &ultimate{symbol->GetUltimate()}; + auto *misc{const_cast<Symbol &>(ultimate).detailsIf<MiscDetails>()}; if (!misc || misc->kind() != MiscDetails::Kind::ConstructName) context().Say(mapper->v.source, "Name '%s' should be a mapper name"_err_en_US, mapper->v.source); else mapper->v.symbol = symbol; } else { - mapper->v.symbol = - &MakeSymbol(mapper->v, MiscDetails{MiscDetails::Kind::ConstructName}); - // TODO: When completing the implementation, we probably want to error if - // the symbol is not declared, but right now, testing that the TODO for - // OmpMapClause happens is obscured by the TODO for declare mapper, so - // leaving this out. Remove the above line once the declare mapper is - // implemented. context().Say(mapper->v.source, "'%s' not - // declared"_err_en_US, mapper->v.source); + // Allow the special 'default' mapper identifier without prior + // declaration so lowering can recognize and handle it. Emit an + // error for any other missing mapper identifier. + if (mapper->v.source.ToString() == "default") { + mapper->v.symbol = &MakeSymbol( + mapper->v, MiscDetails{MiscDetails::Kind::ConstructName}); + } else { + context().Say( + mapper->v.source, "'%s' not declared"_err_en_US, mapper->v.source); + } } } return true; @@ -3614,10 +3617,18 @@ void ModuleVisitor::Post(const parser::UseStmt &x) { rename.u); } for (const auto &[name, symbol] : *useModuleScope_) { + // Default USE imports public names, excluding intrinsic-only and most + // miscellaneous details. However, allow OpenMP mapper identifiers, + // which are currently represented with MiscDetails::ConstructName. + bool isMapper{false}; + if (const auto *misc{symbol->detailsIf<MiscDetails>()}) { + isMapper = misc->kind() == MiscDetails::Kind::ConstructName; + } if (symbol->attrs().test(Attr::PUBLIC) && !IsUseRenamed(symbol->name()) && (!symbol->implicitAttrs().test(Attr::INTRINSIC) || symbol->has<UseDetails>()) && - !symbol->has<MiscDetails>() && useNames.count(name) == 0) { + (!symbol->has<MiscDetails>() || isMapper) && + useNames.count(name) == 0) { SourceName location{x.moduleName.source}; if (auto *localSymbol{FindInScope(name)}) { DoAddUse(location, localSymbol->name(), *localSymbol, *symbol); diff --git a/flang/test/Lower/OpenMP/declare-mapper.f90 b/flang/test/Lower/OpenMP/declare-mapper.f90 index 3d4d0da1e18a3..a5fb0710592ce 100644 --- a/flang/test/Lower/OpenMP/declare-mapper.f90 +++ b/flang/test/Lower/OpenMP/declare-mapper.f90 @@ -6,7 +6,8 @@ ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-3.f90 -o - | FileCheck %t/omp-declare-mapper-3.f90 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-4.f90 -o - | FileCheck %t/omp-declare-mapper-4.f90 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-5.f90 -o - | FileCheck %t/omp-declare-mapper-5.f90 -! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 %t/omp-declare-mapper-6.f90 -o - | FileCheck %t/omp-declare-mapper-6.f90 +! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-6.f90 -o - | FileCheck %t/omp-declare-mapper-6.f90 +! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-7.f90 -o - | FileCheck %t/omp-declare-mapper-7.f90 !--- omp-declare-mapper-1.f90 subroutine declare_mapper_1 @@ -301,3 +302,25 @@ subroutine declare_mapper_nested_parent r%real_arr = r%base_arr(1) + r%inner%deep_arr(1) !$omp end target end subroutine declare_mapper_nested_parent + +!--- omp-declare-mapper-7.f90 +! Check mappers declared inside modules and used via USE association. +module m_mod + implicit none + type :: mty + integer :: x + end type mty + !$omp declare mapper(mymap : mty :: v) map(tofrom: v%x) +end module m_mod + +program use_module_mapper + use m_mod + implicit none + type(mty) :: a + + ! CHECK: omp.declare_mapper @[[MODMAP:[^ ]*mymap]] + ! CHECK: %{{.*}} = omp.map.info {{.*}} mapper(@[[MODMAP]]) {{.*}} {name = "a"} + !$omp target map(mapper(mymap) : a) + a%x = 42 + !$omp end target +end program use_module_mapper diff --git a/flang/test/Parser/OpenMP/map-modifiers.f90 b/flang/test/Parser/OpenMP/map-modifiers.f90 index 83662b70f08f5..7d9b8856ac833 100644 --- a/flang/test/Parser/OpenMP/map-modifiers.f90 +++ b/flang/test/Parser/OpenMP/map-modifiers.f90 @@ -320,7 +320,7 @@ subroutine f21(x, y) integer :: x(10) integer :: y integer, parameter :: p = 23 - !$omp target map(mapper(xx), from: x) + !$omp target map(mapper(default), from: x) x = x + 1 !$omp end target end @@ -329,7 +329,7 @@ subroutine f21(x, y) !UNPARSE: INTEGER x(10_4) !UNPARSE: INTEGER y !UNPARSE: INTEGER, PARAMETER :: p = 23_4 -!UNPARSE: !$OMP TARGET MAP(MAPPER(XX), FROM: X) +!UNPARSE: !$OMP TARGET MAP(MAPPER(DEFAULT), FROM: X) !UNPARSE: x=x+1_4 !UNPARSE: !$OMP END TARGET !UNPARSE: END SUBROUTINE @@ -337,7 +337,7 @@ subroutine f21(x, y) !PARSE-TREE: OmpBeginDirective !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | Modifier -> OmpMapper -> Name = 'xx' +!PARSE-TREE: | | Modifier -> OmpMapper -> Name = 'default' !PARSE-TREE: | | Modifier -> OmpMapType -> Value = From !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' @@ -375,4 +375,3 @@ subroutine f22(x) !PARSE-TREE: | | SectionSubscript -> Integer -> Expr = 'i' !PARSE-TREE: | | | Designator -> DataRef -> Name = 'i' !PARSE-TREE: | bool = 'true' - diff --git a/flang/test/Semantics/OpenMP/map-clause-symbols.f90 b/flang/test/Semantics/OpenMP/map-clause-symbols.f90 index 1d6315b4a2312..cdb65a71e8887 100644 --- a/flang/test/Semantics/OpenMP/map-clause-symbols.f90 +++ b/flang/test/Semantics/OpenMP/map-clause-symbols.f90 @@ -1,6 +1,5 @@ -! RUN: %flang_fc1 -fdebug-dump-symbols -fopenmp -fopenmp-version=50 %s | FileCheck %s +! RUN: not %flang_fc1 -fopenmp -fopenmp-version=50 %s 2>&1 | FileCheck %s program main -!CHECK-LABEL: MainProgram scope: MAIN integer, parameter :: n = 256 real(8) :: a(256) !$omp target map(mapper(xx), from:a) @@ -8,7 +7,6 @@ program main a(i) = 4.2 end do !$omp end target -!CHECK: OtherConstruct scope: size=0 alignment=1 sourceRange=74 bytes -!CHECK: OtherClause scope: size=0 alignment=1 sourceRange=0 bytes -!CHECK: xx: Misc ConstructName end program main + +! CHECK: error: '{{.*}}' not declared |
| @llvm/pr-subscribers-flang-openmp Author: Akash Banerjee (TIFitis) Changes
Fixes #163385. Full diff: https://github.com/llvm/llvm-project/pull/163860.diff 5 Files Affected:
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index 85398be778382..41820c74e3921 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -1402,10 +1402,14 @@ bool ClauseProcessor::processMap( } if (mappers) { assert(mappers->size() == 1 && "more than one mapper"); - mapperIdName = mappers->front().v.id().symbol->name().ToString(); - if (mapperIdName != "default") - mapperIdName = converter.mangleName( - mapperIdName, mappers->front().v.id().symbol->owner()); + const semantics::Symbol *mapperSym = mappers->front().v.id().symbol; + mapperIdName = mapperSym->name().ToString(); + if (mapperIdName != "default") { + // Mangle with the ultimate owner so that use-associated mapper + // identifiers resolve to the same symbol as their defining scope. + const semantics::Symbol &ultimate = mapperSym->GetUltimate(); + mapperIdName = converter.mangleName(mapperIdName, ultimate.owner()); + } } processMapObjects(stmtCtx, clauseLocation, diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index ae0ff9ca8068d..ef45c692acc8c 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1824,21 +1824,24 @@ bool OmpVisitor::Pre(const parser::OmpMapClause &x) { // TODO: Do we need a specific flag or type here, to distinghuish against // other ConstructName things? Leaving this for the full implementation // of mapper lowering. - auto *misc{symbol->detailsIf<MiscDetails>()}; + const Symbol &ultimate{symbol->GetUltimate()}; + auto *misc{const_cast<Symbol &>(ultimate).detailsIf<MiscDetails>()}; if (!misc || misc->kind() != MiscDetails::Kind::ConstructName) context().Say(mapper->v.source, "Name '%s' should be a mapper name"_err_en_US, mapper->v.source); else mapper->v.symbol = symbol; } else { - mapper->v.symbol = - &MakeSymbol(mapper->v, MiscDetails{MiscDetails::Kind::ConstructName}); - // TODO: When completing the implementation, we probably want to error if - // the symbol is not declared, but right now, testing that the TODO for - // OmpMapClause happens is obscured by the TODO for declare mapper, so - // leaving this out. Remove the above line once the declare mapper is - // implemented. context().Say(mapper->v.source, "'%s' not - // declared"_err_en_US, mapper->v.source); + // Allow the special 'default' mapper identifier without prior + // declaration so lowering can recognize and handle it. Emit an + // error for any other missing mapper identifier. + if (mapper->v.source.ToString() == "default") { + mapper->v.symbol = &MakeSymbol( + mapper->v, MiscDetails{MiscDetails::Kind::ConstructName}); + } else { + context().Say( + mapper->v.source, "'%s' not declared"_err_en_US, mapper->v.source); + } } } return true; @@ -3614,10 +3617,18 @@ void ModuleVisitor::Post(const parser::UseStmt &x) { rename.u); } for (const auto &[name, symbol] : *useModuleScope_) { + // Default USE imports public names, excluding intrinsic-only and most + // miscellaneous details. However, allow OpenMP mapper identifiers, + // which are currently represented with MiscDetails::ConstructName. + bool isMapper{false}; + if (const auto *misc{symbol->detailsIf<MiscDetails>()}) { + isMapper = misc->kind() == MiscDetails::Kind::ConstructName; + } if (symbol->attrs().test(Attr::PUBLIC) && !IsUseRenamed(symbol->name()) && (!symbol->implicitAttrs().test(Attr::INTRINSIC) || symbol->has<UseDetails>()) && - !symbol->has<MiscDetails>() && useNames.count(name) == 0) { + (!symbol->has<MiscDetails>() || isMapper) && + useNames.count(name) == 0) { SourceName location{x.moduleName.source}; if (auto *localSymbol{FindInScope(name)}) { DoAddUse(location, localSymbol->name(), *localSymbol, *symbol); diff --git a/flang/test/Lower/OpenMP/declare-mapper.f90 b/flang/test/Lower/OpenMP/declare-mapper.f90 index 3d4d0da1e18a3..a5fb0710592ce 100644 --- a/flang/test/Lower/OpenMP/declare-mapper.f90 +++ b/flang/test/Lower/OpenMP/declare-mapper.f90 @@ -6,7 +6,8 @@ ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-3.f90 -o - | FileCheck %t/omp-declare-mapper-3.f90 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-4.f90 -o - | FileCheck %t/omp-declare-mapper-4.f90 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-5.f90 -o - | FileCheck %t/omp-declare-mapper-5.f90 -! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 %t/omp-declare-mapper-6.f90 -o - | FileCheck %t/omp-declare-mapper-6.f90 +! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-6.f90 -o - | FileCheck %t/omp-declare-mapper-6.f90 +! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-7.f90 -o - | FileCheck %t/omp-declare-mapper-7.f90 !--- omp-declare-mapper-1.f90 subroutine declare_mapper_1 @@ -301,3 +302,25 @@ subroutine declare_mapper_nested_parent r%real_arr = r%base_arr(1) + r%inner%deep_arr(1) !$omp end target end subroutine declare_mapper_nested_parent + +!--- omp-declare-mapper-7.f90 +! Check mappers declared inside modules and used via USE association. +module m_mod + implicit none + type :: mty + integer :: x + end type mty + !$omp declare mapper(mymap : mty :: v) map(tofrom: v%x) +end module m_mod + +program use_module_mapper + use m_mod + implicit none + type(mty) :: a + + ! CHECK: omp.declare_mapper @[[MODMAP:[^ ]*mymap]] + ! CHECK: %{{.*}} = omp.map.info {{.*}} mapper(@[[MODMAP]]) {{.*}} {name = "a"} + !$omp target map(mapper(mymap) : a) + a%x = 42 + !$omp end target +end program use_module_mapper diff --git a/flang/test/Parser/OpenMP/map-modifiers.f90 b/flang/test/Parser/OpenMP/map-modifiers.f90 index 83662b70f08f5..7d9b8856ac833 100644 --- a/flang/test/Parser/OpenMP/map-modifiers.f90 +++ b/flang/test/Parser/OpenMP/map-modifiers.f90 @@ -320,7 +320,7 @@ subroutine f21(x, y) integer :: x(10) integer :: y integer, parameter :: p = 23 - !$omp target map(mapper(xx), from: x) + !$omp target map(mapper(default), from: x) x = x + 1 !$omp end target end @@ -329,7 +329,7 @@ subroutine f21(x, y) !UNPARSE: INTEGER x(10_4) !UNPARSE: INTEGER y !UNPARSE: INTEGER, PARAMETER :: p = 23_4 -!UNPARSE: !$OMP TARGET MAP(MAPPER(XX), FROM: X) +!UNPARSE: !$OMP TARGET MAP(MAPPER(DEFAULT), FROM: X) !UNPARSE: x=x+1_4 !UNPARSE: !$OMP END TARGET !UNPARSE: END SUBROUTINE @@ -337,7 +337,7 @@ subroutine f21(x, y) !PARSE-TREE: OmpBeginDirective !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | Modifier -> OmpMapper -> Name = 'xx' +!PARSE-TREE: | | Modifier -> OmpMapper -> Name = 'default' !PARSE-TREE: | | Modifier -> OmpMapType -> Value = From !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' @@ -375,4 +375,3 @@ subroutine f22(x) !PARSE-TREE: | | SectionSubscript -> Integer -> Expr = 'i' !PARSE-TREE: | | | Designator -> DataRef -> Name = 'i' !PARSE-TREE: | bool = 'true' - diff --git a/flang/test/Semantics/OpenMP/map-clause-symbols.f90 b/flang/test/Semantics/OpenMP/map-clause-symbols.f90 index 1d6315b4a2312..cdb65a71e8887 100644 --- a/flang/test/Semantics/OpenMP/map-clause-symbols.f90 +++ b/flang/test/Semantics/OpenMP/map-clause-symbols.f90 @@ -1,6 +1,5 @@ -! RUN: %flang_fc1 -fdebug-dump-symbols -fopenmp -fopenmp-version=50 %s | FileCheck %s +! RUN: not %flang_fc1 -fopenmp -fopenmp-version=50 %s 2>&1 | FileCheck %s program main -!CHECK-LABEL: MainProgram scope: MAIN integer, parameter :: n = 256 real(8) :: a(256) !$omp target map(mapper(xx), from:a) @@ -8,7 +7,6 @@ program main a(i) = 4.2 end do !$omp end target -!CHECK: OtherConstruct scope: size=0 alignment=1 sourceRange=74 bytes -!CHECK: OtherClause scope: size=0 alignment=1 sourceRange=0 bytes -!CHECK: xx: Misc ConstructName end program main + +! CHECK: error: '{{.*}}' not declared |
| @llvm/pr-subscribers-flang-semantics Author: Akash Banerjee (TIFitis) Changes
Fixes #163385. Full diff: https://github.com/llvm/llvm-project/pull/163860.diff 5 Files Affected:
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index 85398be778382..41820c74e3921 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -1402,10 +1402,14 @@ bool ClauseProcessor::processMap( } if (mappers) { assert(mappers->size() == 1 && "more than one mapper"); - mapperIdName = mappers->front().v.id().symbol->name().ToString(); - if (mapperIdName != "default") - mapperIdName = converter.mangleName( - mapperIdName, mappers->front().v.id().symbol->owner()); + const semantics::Symbol *mapperSym = mappers->front().v.id().symbol; + mapperIdName = mapperSym->name().ToString(); + if (mapperIdName != "default") { + // Mangle with the ultimate owner so that use-associated mapper + // identifiers resolve to the same symbol as their defining scope. + const semantics::Symbol &ultimate = mapperSym->GetUltimate(); + mapperIdName = converter.mangleName(mapperIdName, ultimate.owner()); + } } processMapObjects(stmtCtx, clauseLocation, diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index ae0ff9ca8068d..ef45c692acc8c 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1824,21 +1824,24 @@ bool OmpVisitor::Pre(const parser::OmpMapClause &x) { // TODO: Do we need a specific flag or type here, to distinghuish against // other ConstructName things? Leaving this for the full implementation // of mapper lowering. - auto *misc{symbol->detailsIf<MiscDetails>()}; + const Symbol &ultimate{symbol->GetUltimate()}; + auto *misc{const_cast<Symbol &>(ultimate).detailsIf<MiscDetails>()}; if (!misc || misc->kind() != MiscDetails::Kind::ConstructName) context().Say(mapper->v.source, "Name '%s' should be a mapper name"_err_en_US, mapper->v.source); else mapper->v.symbol = symbol; } else { - mapper->v.symbol = - &MakeSymbol(mapper->v, MiscDetails{MiscDetails::Kind::ConstructName}); - // TODO: When completing the implementation, we probably want to error if - // the symbol is not declared, but right now, testing that the TODO for - // OmpMapClause happens is obscured by the TODO for declare mapper, so - // leaving this out. Remove the above line once the declare mapper is - // implemented. context().Say(mapper->v.source, "'%s' not - // declared"_err_en_US, mapper->v.source); + // Allow the special 'default' mapper identifier without prior + // declaration so lowering can recognize and handle it. Emit an + // error for any other missing mapper identifier. + if (mapper->v.source.ToString() == "default") { + mapper->v.symbol = &MakeSymbol( + mapper->v, MiscDetails{MiscDetails::Kind::ConstructName}); + } else { + context().Say( + mapper->v.source, "'%s' not declared"_err_en_US, mapper->v.source); + } } } return true; @@ -3614,10 +3617,18 @@ void ModuleVisitor::Post(const parser::UseStmt &x) { rename.u); } for (const auto &[name, symbol] : *useModuleScope_) { + // Default USE imports public names, excluding intrinsic-only and most + // miscellaneous details. However, allow OpenMP mapper identifiers, + // which are currently represented with MiscDetails::ConstructName. + bool isMapper{false}; + if (const auto *misc{symbol->detailsIf<MiscDetails>()}) { + isMapper = misc->kind() == MiscDetails::Kind::ConstructName; + } if (symbol->attrs().test(Attr::PUBLIC) && !IsUseRenamed(symbol->name()) && (!symbol->implicitAttrs().test(Attr::INTRINSIC) || symbol->has<UseDetails>()) && - !symbol->has<MiscDetails>() && useNames.count(name) == 0) { + (!symbol->has<MiscDetails>() || isMapper) && + useNames.count(name) == 0) { SourceName location{x.moduleName.source}; if (auto *localSymbol{FindInScope(name)}) { DoAddUse(location, localSymbol->name(), *localSymbol, *symbol); diff --git a/flang/test/Lower/OpenMP/declare-mapper.f90 b/flang/test/Lower/OpenMP/declare-mapper.f90 index 3d4d0da1e18a3..a5fb0710592ce 100644 --- a/flang/test/Lower/OpenMP/declare-mapper.f90 +++ b/flang/test/Lower/OpenMP/declare-mapper.f90 @@ -6,7 +6,8 @@ ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-3.f90 -o - | FileCheck %t/omp-declare-mapper-3.f90 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-4.f90 -o - | FileCheck %t/omp-declare-mapper-4.f90 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-5.f90 -o - | FileCheck %t/omp-declare-mapper-5.f90 -! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 %t/omp-declare-mapper-6.f90 -o - | FileCheck %t/omp-declare-mapper-6.f90 +! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-6.f90 -o - | FileCheck %t/omp-declare-mapper-6.f90 +! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-7.f90 -o - | FileCheck %t/omp-declare-mapper-7.f90 !--- omp-declare-mapper-1.f90 subroutine declare_mapper_1 @@ -301,3 +302,25 @@ subroutine declare_mapper_nested_parent r%real_arr = r%base_arr(1) + r%inner%deep_arr(1) !$omp end target end subroutine declare_mapper_nested_parent + +!--- omp-declare-mapper-7.f90 +! Check mappers declared inside modules and used via USE association. +module m_mod + implicit none + type :: mty + integer :: x + end type mty + !$omp declare mapper(mymap : mty :: v) map(tofrom: v%x) +end module m_mod + +program use_module_mapper + use m_mod + implicit none + type(mty) :: a + + ! CHECK: omp.declare_mapper @[[MODMAP:[^ ]*mymap]] + ! CHECK: %{{.*}} = omp.map.info {{.*}} mapper(@[[MODMAP]]) {{.*}} {name = "a"} + !$omp target map(mapper(mymap) : a) + a%x = 42 + !$omp end target +end program use_module_mapper diff --git a/flang/test/Parser/OpenMP/map-modifiers.f90 b/flang/test/Parser/OpenMP/map-modifiers.f90 index 83662b70f08f5..7d9b8856ac833 100644 --- a/flang/test/Parser/OpenMP/map-modifiers.f90 +++ b/flang/test/Parser/OpenMP/map-modifiers.f90 @@ -320,7 +320,7 @@ subroutine f21(x, y) integer :: x(10) integer :: y integer, parameter :: p = 23 - !$omp target map(mapper(xx), from: x) + !$omp target map(mapper(default), from: x) x = x + 1 !$omp end target end @@ -329,7 +329,7 @@ subroutine f21(x, y) !UNPARSE: INTEGER x(10_4) !UNPARSE: INTEGER y !UNPARSE: INTEGER, PARAMETER :: p = 23_4 -!UNPARSE: !$OMP TARGET MAP(MAPPER(XX), FROM: X) +!UNPARSE: !$OMP TARGET MAP(MAPPER(DEFAULT), FROM: X) !UNPARSE: x=x+1_4 !UNPARSE: !$OMP END TARGET !UNPARSE: END SUBROUTINE @@ -337,7 +337,7 @@ subroutine f21(x, y) !PARSE-TREE: OmpBeginDirective !PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | Modifier -> OmpMapper -> Name = 'xx' +!PARSE-TREE: | | Modifier -> OmpMapper -> Name = 'default' !PARSE-TREE: | | Modifier -> OmpMapType -> Value = From !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' @@ -375,4 +375,3 @@ subroutine f22(x) !PARSE-TREE: | | SectionSubscript -> Integer -> Expr = 'i' !PARSE-TREE: | | | Designator -> DataRef -> Name = 'i' !PARSE-TREE: | bool = 'true' - diff --git a/flang/test/Semantics/OpenMP/map-clause-symbols.f90 b/flang/test/Semantics/OpenMP/map-clause-symbols.f90 index 1d6315b4a2312..cdb65a71e8887 100644 --- a/flang/test/Semantics/OpenMP/map-clause-symbols.f90 +++ b/flang/test/Semantics/OpenMP/map-clause-symbols.f90 @@ -1,6 +1,5 @@ -! RUN: %flang_fc1 -fdebug-dump-symbols -fopenmp -fopenmp-version=50 %s | FileCheck %s +! RUN: not %flang_fc1 -fopenmp -fopenmp-version=50 %s 2>&1 | FileCheck %s program main -!CHECK-LABEL: MainProgram scope: MAIN integer, parameter :: n = 256 real(8) :: a(256) !$omp target map(mapper(xx), from:a) @@ -8,7 +7,6 @@ program main a(i) = 4.2 end do !$omp end target -!CHECK: OtherConstruct scope: size=0 alignment=1 sourceRange=74 bytes -!CHECK: OtherClause scope: size=0 alignment=1 sourceRange=0 bytes -!CHECK: xx: Misc ConstructName end program main + +! CHECK: error: '{{.*}}' not declared |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes the handling of OpenMP declare mapper identifiers when they are imported via USE statements from modules. The changes address issue #163385 by implementing proper semantic checking for undeclared mappers and ensuring mapper lookup includes module-imported identifiers.
Key Changes
- Implemented semantic error checking to catch undeclared mapper identifiers (except for the special "default" mapper)
- Fixed mapper symbol resolution to use the ultimate symbol owner for proper mangling when mappers are imported via USE
- Added support for importing OpenMP mapper identifiers through module USE statements
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| flang/test/Semantics/OpenMP/map-clause-symbols.f90 | Updated test to verify error reporting for undeclared mapper identifiers |
| flang/test/Parser/OpenMP/map-modifiers.f90 | Changed test to use "default" mapper instead of undeclared "xx" mapper |
| flang/test/Lower/OpenMP/declare-mapper.f90 | Added new test case for mapper usage via module USE association |
| flang/lib/Semantics/resolve-names.cpp | Implemented error checking for undeclared mappers and enabled mapper import through USE statements |
| flang/lib/Lower/OpenMP/ClauseProcessor.cpp | Fixed mapper name mangling to use ultimate symbol owner for use-associated mappers |
| I don't see changes to add support (in lib/Semantics/mod-file.cpp) for emitting the |
I think it gets added here - llvm-project/flang/lib/Lower/OpenMP/OpenMP.cpp Line 3583 in 48a99ad
|
| Ping for review. |
I meant the module file (m_mod.mod) should have an entry for the declare mapper. Without this how will the mapper in Does the FIR/OMP code generation generate a dummy declare mapper if none is found? If so that is not complete. |
| @kiranchandramohan Sorry for the earlier misunderstanding — I’m not very familiar with the parsing/semantic side of things. It was working without exporting to the .mod file because the test originally had both the module and the program in the same file. Once separated, it started failing. I’ve now updated the PR to export the declare mapper to the .mod file as you suggested, and the lookup works correctly when compiling across different files. I’ve also updated the test accordingly. As far as I’m aware, FIR/OMP does not emit dummy mappers at any stage. |
Thanks for the updates. I have a question and two requests for tests. |
| // Walk scopes and materialize omp.declare_mapper ops for mapper declarations | ||
| // found in imported modules. If \p scope is null, start from the global scope. | ||
| void Fortran::lower::materializeOpenMPDeclareMappers( | ||
| Fortran::lower::AbstractConverter &converter, | ||
| semantics::SemanticsContext &semaCtx, const semantics::Scope *scope) { | ||
| const semantics::Scope &root = scope ? *scope : semaCtx.globalScope(); | ||
| | ||
| // Recurse into child scopes first (modules, submodules, etc.). | ||
| for (const semantics::Scope &child : root.children()) | ||
| materializeOpenMPDeclareMappers(converter, semaCtx, &child); | ||
| | ||
| // Only consider module scopes to avoid duplicating local constructs. | ||
| if (!root.IsModule()) | ||
| return; | ||
| | ||
| // Scan symbols in this module scope for MapperDetails. | ||
| for (auto &it : root) { | ||
| const semantics::Symbol &sym = *it.second; | ||
| if (auto *md = sym.detailsIf<semantics::MapperDetails>()) { | ||
| for (const auto *decl : md->GetDeclList()) { | ||
| if (const auto *mapperDecl = | ||
| std::get_if<parser::OpenMPDeclareMapperConstruct>(&decl->u)) { | ||
| genOpenMPDeclareMapperImpl(converter, semaCtx, *mapperDecl, &sym); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need this function? Can you check how threadprivate works and whether it needs this kind of handling?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Threadprivate directive is serialised into the .mod, and we don't need to lookup symbols by name. We need to lookup existing declare mappers in the module when they are referred to through mapper modifiers, as such, I think we need the materializeOpenMPDeclareMappers function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to recursively go through all the scopes? Or are only the declare mappers at the top-level needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If X uses module A and A USEs module B (B from a .mod), B’s mappers will live under A’s scope in the semantics tree. Without recursion, B’s mappers would be skipped, and map(mapper(...)) using B’s mapper would not resolve.
Otherwise, we already early-return for local scopes and non .mod files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you help me understand, how is this different from emitting declarations for functions or module variables? And why is it sufficient for module functions but a recursive traversal required for declare mappers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed the approach we use to define the inherited declare mappers. Instead of defining them as a pre-process step, I've switched it to a lazy approach when the mapper is referred in the body.
Let me know if you're happy with this approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't requesting you to change the approach here. I was trying to understand why we needed additional recursive handling for the declare mapper directives compared to module functions.
I think the previous method of eagerly generating declare mappers is more appropriate than lazy generation. Unless you are convinced that eager generation is not correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've reverted to the previous approach.
From what I understand, a function that comes in through a transitive USE is represented in the importing scope by a symbol whose details are semantics::UseDetails, pointing back to the defining symbol in the original module. When lowering sees a call, it follows that chain to the ultimate symbol in the source module, so the call is generated exactly as if the function were imported directly. No IR for the callee is emitted in the current compilation unit.
For declare mappers, we need to follow the chain and generate the IR. So we can either take the lazy approach, or we must go through the scopes to find any declare mappers that have brought in through USE modules and lower them.
The declare mappers don't seem to appear at the top-level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
| // Ensure imported OpenMP declare mappers are materialized at module | ||
| // scope before lowering any constructs that may reference them. | ||
| createBuilderOutsideOfFuncOpAndDo([&]() { | ||
| Fortran::lower::materializeOpenMPDeclareMappers( | ||
| *this, bridge.getSemanticsContext()); | ||
| }); | ||
| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the createBuilderOutsideOfFuncOpAndDo function above this visit all the top level OpenMP directives? if so is it possible to move this there and just create the Declare Mapper operation while visiting OpenMP directives?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can't move this above for the same reason stated above.
| ✅ With the latest revision this PR passed the C/C++ code formatter. |
- Implemented semantic TODO to catch undeclared mappers. - Fix mapper lookup to include modules imported through USE. - Update and add tests. Fixes llvm#163385.
…e and program file compilation.
e98f7a7 to 83b7885 Compare 83b7885 to 83ab55c Compare
kiranchandramohan left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will be away for atleast a week. This needs further review from @agozillon @skatrak or @kparzysz
Approving to signal that I am not blocking the progress of the patch.
Thanks for the review 👍🏽 |
| Ping for review. |
| The semantic parts look ok to me. Presumably we would do the same thing for user-declared reductions in terms of code generation. @jsjodin: does this look like what you're doing? |
kparzysz left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks reasonable. If some parts turn out to be unnecessary, we can remove them later.
…se-module" (#167896) Reverts llvm/llvm-project#163860
Fixes #163385.