Skip to content
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
042d2f6
[flang] Draft of the work to look up COMMON declarations in the modules
eugeneepshteyn Oct 6, 2025
f31c976
Merge branch 'main' into 2-acc-common
eugeneepshteyn Oct 6, 2025
931b300
Try to handle use association, but didn't work, because no symbol
eugeneepshteyn Oct 9, 2025
0bfb06c
Merge branch 'main' into 2-acc-common
eugeneepshteyn Oct 9, 2025
86cb8b6
Searching for COMMON definition in top level modules
eugeneepshteyn Oct 9, 2025
f462bf5
Guard against null cb
eugeneepshteyn Oct 9, 2025
14ce6b6
Unit test
eugeneepshteyn Oct 9, 2025
8c344c3
Merge branch 'llvm:main' into 2-acc-common
eugeneepshteyn Oct 9, 2025
e00d8f5
Merge branch '2-acc-common' into 3-acc-common
eugeneepshteyn Oct 10, 2025
827f8f0
Merge branch 'llvm:main' into 3-acc-common
eugeneepshteyn Oct 12, 2025
430660f
Merge branch 'llvm:main' into 3-acc-common
eugeneepshteyn Oct 13, 2025
ff637dd
Updated Scope::FindCommonBlock() to be similar to Scope::FindSymbol()…
eugeneepshteyn Oct 13, 2025
9e19979
clang-format
eugeneepshteyn Oct 13, 2025
66028ef
Split FindCommonBlock() into FindCB() and FindCommonBlockInScopes(). …
eugeneepshteyn Oct 13, 2025
41336f1
Add USE association details to COMMON blocks
eugeneepshteyn Oct 13, 2025
eac75b7
Handle the case of redeclared COMMON block
eugeneepshteyn Oct 13, 2025
553a3c3
clang-format
eugeneepshteyn Oct 13, 2025
63662d8
Merge branch 'llvm:main' into 3-acc-common
eugeneepshteyn Oct 13, 2025
adcd69b
Merge branch 'llvm:main' into 2-acc-common
eugeneepshteyn Oct 13, 2025
74de636
Merge branch '3-acc-common' into 2-acc-common
eugeneepshteyn Oct 13, 2025
6527159
Merge branch 'llvm:main' into 3-acc-common
eugeneepshteyn Oct 16, 2025
c042379
Code review feedback + separated COMMON lists into COMMON in the curr…
eugeneepshteyn Oct 16, 2025
740894f
COMMON block uses renames. Extended test to using module chain
eugeneepshteyn Oct 16, 2025
ca82173
clang-format
eugeneepshteyn Oct 16, 2025
2474da0
Enabled creating of USE symbols from USE symbols of COMMON blocks
eugeneepshteyn Oct 16, 2025
68363d2
Merge branch 'llvm:main' into 3-acc-common
eugeneepshteyn Oct 16, 2025
5c84d48
clang-format
eugeneepshteyn Oct 16, 2025
cc4145c
Merge branch 'llvm:main' into 2-acc-common
eugeneepshteyn Oct 16, 2025
06b2a01
Merge branch '3-acc-common' into 2-acc-common
eugeneepshteyn Oct 16, 2025
8f802f7
Code review feedback
eugeneepshteyn Oct 16, 2025
b711009
Renamed to FindCommonBlockInVisibleScope()
eugeneepshteyn Oct 17, 2025
ee0cdde
clang-format
eugeneepshteyn Oct 17, 2025
5349a65
Merge branch 'llvm:main' into 2-acc-common
eugeneepshteyn Oct 17, 2025
b268f4e
Merge branch 'llvm:main' into 3-acc-common
eugeneepshteyn Oct 20, 2025
6c8e7a0
Code review feedback
eugeneepshteyn Oct 16, 2025
bab4e67
Renamed to FindCommonBlockInVisibleScope()
eugeneepshteyn Oct 17, 2025
ab01526
clang-format
eugeneepshteyn Oct 17, 2025
f2028c7
Code review feedback
eugeneepshteyn Oct 20, 2025
258050f
Merge branch 'llvm:main' into 3-acc-common
eugeneepshteyn Oct 20, 2025
adf6b5f
Merge branch 'llvm:main' into 2-acc-common
eugeneepshteyn Oct 20, 2025
86dc6a7
Merge branch '3-acc-common' into 2-acc-common
eugeneepshteyn Oct 20, 2025
acde775
clang-format
eugeneepshteyn Oct 20, 2025
abd2f40
[AddOrUpdateCommonBlockUse] Implemented selection of largest COMMON b…
eugeneepshteyn Oct 20, 2025
fc6beb7
[AddOrUpdateCommonBlockUse] Implemented selection of largest COMMON b…
eugeneepshteyn Oct 20, 2025
19c1534
clang-format
eugeneepshteyn Oct 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions flang/include/flang/Semantics/scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,23 @@ class Scope {
mapType &commonBlocks() { return commonBlocks_; }
const mapType &commonBlocks() const { return commonBlocks_; }
Symbol &MakeCommonBlock(SourceName, SourceName location);
bool AddCommonBlock(const SourceName &name, Symbol &cbSymbol);

/// Find COMMON block in the current scope
Symbol *FindCB(const SourceName &name) const {
if (const auto it{commonBlocks_.find(name)}; it != commonBlocks_.end()) {
return &*it->second;
}
return nullptr;
}

/// Find COMMON block that is not USE-associated in the current scope
Symbol *FindCommonBlock(const SourceName &) const;

/// Find COMMON block in current and surrounding scopes, follow USE
/// associations
Symbol *FindCommonBlockInScopes(const SourceName &) const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name could be more precise so that it's immediately understandable at call sites.


/// Make a Symbol but don't add it to the scope.
template <typename D>
common::IfNoLvalue<Symbol &, D> MakeSymbol(
Expand Down
2 changes: 1 addition & 1 deletion flang/include/flang/Semantics/symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,7 @@ class Symbol {
const Details &details() const { return details_; }
// Assign the details of the symbol from one of the variants.
// Only allowed in certain cases.
void set_details(Details &&);
void set_details(Details &&, bool force = false);

// Can the details of this symbol be replaced with the given details?
bool CanReplaceDetails(const Details &details) const;
Expand Down
5 changes: 4 additions & 1 deletion flang/lib/Semantics/check-declarations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2782,7 +2782,10 @@ void CheckHelper::Check(const Scope &scope) {
Check(*scope.symbol());
}
for (const auto &pair : scope.commonBlocks()) {
CheckCommonBlock(*pair.second);
if (pair.second->has<CommonBlockDetails>()) {
// Only process actual COMMON block objects, not their uses
CheckCommonBlock(*pair.second);
}
}
int mainProgCnt{0};
for (const Scope &child : scope.children()) {
Expand Down
5 changes: 4 additions & 1 deletion flang/lib/Semantics/compute-offsets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,10 @@ void ComputeOffsetsHelper::Compute(Scope &scope) {
// where COMMON blocks are illegal (C1107 and C1108).
if (scope.kind() != Scope::Kind::BlockConstruct) {
for (auto &pair : scope.commonBlocks()) {
DoCommonBlock(*pair.second);
// Only process actual COMMON block objects, not their uses
if (pair.second->has<CommonBlockDetails>()) {
DoCommonBlock(*pair.second);
}
}
}
for (auto &[symbol, dep] : dependents_) {
Expand Down
21 changes: 8 additions & 13 deletions flang/lib/Semantics/resolve-directives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1695,17 +1695,12 @@ void AccAttributeVisitor::Post(const parser::Name &name) {

Symbol *AccAttributeVisitor::ResolveAccCommonBlockName(
const parser::Name *name) {
if (auto *prev{name
? GetContext().scope.parent().FindCommonBlock(name->source)
: nullptr}) {
name->symbol = prev;
return prev;
}
// Check if the Common Block is declared in the current scope
if (auto *commonBlockSymbol{
name ? GetContext().scope.FindCommonBlock(name->source) : nullptr}) {
name->symbol = commonBlockSymbol;
return commonBlockSymbol;
if (!name) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be more clear as if (name) { ..., I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

return nullptr;
}
if (auto *cb{GetContext().scope.FindCommonBlockInScopes(name->source)}) {
name->symbol = cb;
return cb;
}
return nullptr;
}
Expand Down Expand Up @@ -1755,8 +1750,8 @@ void AccAttributeVisitor::ResolveAccObject(
}
} else {
context_.Say(name.source,
"COMMON block must be declared in the same scoping unit "
"in which the OpenACC directive or clause appears"_err_en_US);
"Could not find COMMON block '%s' used in OpenACC directive"_err_en_US,
name.ToString());
}
},
},
Expand Down
15 changes: 15 additions & 0 deletions flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3627,6 +3627,17 @@ void ModuleVisitor::Post(const parser::UseStmt &x) {
}
}
}
// Go through the list of COMMON block symbols in the module scope and add
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when the same COMMON block name arrives from multiple modules?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first use will be added via AddCommonBlockUse(), but adding the second use will silently fail. What should be the behavior in such case?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know. Maybe you would want to retain the largest definition of the COMMON block, and perhaps warn if their sizes differ.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COMMON block names and sizes are already stored in SemanticsContext, available via SemanticsContext::GetCommonBlocks(). This is what lowering is using to generate correctly sized blob for COMMON.

We already have a warning for COMMON size differences. The following code

module common_multi_mod_a
  integer :: a
  common /my_common/ a
end module

module common_multi_mod_b
  integer :: b
  integer :: c
  common /my_common/ b, c
end module

subroutine s1()
  use common_multi_mod_a
  a = 1
end subroutine

subroutine s2()
  use common_multi_mod_b
  b = 2
  c = 3
end subroutine

subroutine s3()
  use common_multi_mod_b
  use common_multi_mod_a
  a = 4
  b = 5
  c = 6
end subroutine

... generates the following warning:

$ flang -c common-multi-mod.f90 -pedantic
./common-multi-mod.f90:9:11: portability: A named COMMON block should have the same size everywhere it appears (8 bytes here) [-Wdistinct-common-sizes]
    common /my_common/ b, c
            ^^^^^^^^^
./common-multi-mod.f90:3:11: Previously defined with a size of 4 bytes
    common /my_common/ a
            ^^^^^^^^^

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Note that a and b in the example above occupy the same space. We don't warn about that. Should we?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's storage association.

Copy link
Contributor Author

@eugeneepshteyn eugeneepshteyn Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you would want to retain the largest definition of the COMMON block

I implemented that, but unfortunately in PerformStatementSemantics(), ResolveNames() is called before ComputeOffsets(), so don't know COMMON block sizes at the time of the name resolution. I undid my implementation, but kept AddCommonBlockUse() change

// their USE association to the current scope's COMMON blocks.
for (const auto &[name, symbol] : useModuleScope_->commonBlocks()) {
if (auto *localCB{currScope().FindCommonBlockInScopes(name)}; !localCB) {
// Make a symbol, but don't add it to the Scope, since it needs to
// be added to the COMMON blocks
localCB = &currScope().MakeSymbol(
name, symbol->attrs(), UseDetails{name, symbol->GetUltimate()});
currScope().AddCommonBlock(name, *localCB);
}
}
useModuleScope_ = nullptr;
}

Expand Down Expand Up @@ -7284,6 +7295,10 @@ void DeclarationVisitor::CheckCommonBlocks() {
// check for empty common blocks
for (const auto &pair : currScope().commonBlocks()) {
const auto &symbol{*pair.second};
if (!pair.second->has<CommonBlockDetails>()) {
// Skip USE associated COMMON blocks
continue;
}
if (symbol.get<CommonBlockDetails>().objects().empty() &&
symbol.attrs().test(Attr::BIND_C)) {
Say(symbol.name(),
Expand Down
54 changes: 49 additions & 5 deletions flang/lib/Semantics/scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,19 +144,58 @@ void Scope::add_crayPointer(const SourceName &name, Symbol &pointer) {
}

Symbol &Scope::MakeCommonBlock(SourceName name, SourceName location) {
const auto it{commonBlocks_.find(name)};
if (it != commonBlocks_.end()) {
return *it->second;
if (auto *cb{FindCB(name)}) {
if (cb->has<UseDetails>()) {
// COMMON blocks could be re-declared. Example:
// module test
// integer :: a
// common /blk/ a
// end module test
// program main
// use test ! Initially get /blk/ with UseDetails
// integer :: a1
// common /blk/ a1 ! Update with CommonBlockDetails
// end program main
// Reset details with real COMMON block details.
cb->set_details(CommonBlockDetails{name.empty() ? location : name},
/*force*/ true);
}
return *cb;
} else {
Symbol &symbol{MakeSymbol(
name, Attrs{}, CommonBlockDetails{name.empty() ? location : name})};
commonBlocks_.emplace(name, symbol);
return symbol;
}
}

Symbol *Scope::FindCommonBlock(const SourceName &name) const {
const auto it{commonBlocks_.find(name)};
return it != commonBlocks_.end() ? &*it->second : nullptr;
if (auto *cb{FindCB(name)}) {
// Ensure this COMMON block is not USE-associated
if (cb->has<UseDetails>()) {
cb = nullptr;
}
return cb;
}
return nullptr;
}

Symbol *Scope::FindCommonBlockInScopes(const SourceName &name) const {
if (auto *cb{FindCB(name)}) {
return &cb->GetUltimate();
} else if (IsSubmodule()) {
if (const Scope *parent{
symbol_ ? symbol_->get<ModuleDetails>().parent() : nullptr}) {
if (auto *cb{parent->FindCommonBlockInScopes(name)}) {
return &cb->GetUltimate();
}
}
} else if (!IsTopLevel() && parent_) {
if (auto *cb{parent_->FindCommonBlockInScopes(name)}) {
return &cb->GetUltimate();
}
}
return nullptr;
}

Scope *Scope::FindSubmodule(const SourceName &name) const {
Expand All @@ -167,6 +206,11 @@ Scope *Scope::FindSubmodule(const SourceName &name) const {
return &*it->second;
}
}

bool Scope::AddCommonBlock(const SourceName &name, Symbol &cbSymbol) {
return commonBlocks_.emplace(name, cbSymbol).second;
}

bool Scope::AddSubmodule(const SourceName &name, Scope &submodule) {
return submodules_.emplace(name, submodule).second;
}
Expand Down
6 changes: 4 additions & 2 deletions flang/lib/Semantics/symbol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,10 @@ std::string DetailsToString(const Details &details) {

std::string Symbol::GetDetailsName() const { return DetailsToString(details_); }

void Symbol::set_details(Details &&details) {
CHECK(CanReplaceDetails(details));
void Symbol::set_details(Details &&details, bool force) {
if (!force) {
CHECK(CanReplaceDetails(details));
}
details_ = std::move(details);
}

Expand Down
19 changes: 19 additions & 0 deletions flang/test/Semantics/OpenACC/acc-common.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
! RUN: %python %S/../test_errors.py %s %flang -fopenacc
module acc_common_decl
implicit none
integer a
common /a_common/ a
!$acc declare create (/a_common/)
data a/42/
end module acc_common_decl

program acc_decl_test
use acc_common_decl
implicit none

a = 1
!$acc update device (/a_common/)
a = 2
!ERROR: Could not find COMMON block 'a_common_bad' used in OpenACC directive
!$acc update device (/a_common_bad/)
end program