Files
llvm-project/flang/lib/Lower/SymbolMap.cpp
jeanPerier 2aa345054f [flang][OpenACC] remap component references in structured constructs (#171501)
OpenACC data clauses of structured constructs may contain component
references (`obj%comp`, or `obj%array(i:j:k)`, ...).

This changes allows using the ACC dialect data operation result for such
clauses every time the component is referred to inside the scope of the
construct.

The bulk of the change is to add the ability to map
`evaluate::Component` to mlir values in the symbol map used in lowering.
This is done by adding the `ComponentMap` helper class to the lowering
symbol map, and using it to override `evaluate::Component` reference
lowering in expression lowering (ConvertExprToHLFIR.cpp).

Some changes are made in Lower/Support/Utils.h in order to set-up/expose
the hashing/equality helpers needed to use `evaluate::Component` in
llvm::DenseMap.

In OpenACC.cpp, `genPrivatizationRecipes` and `genDataOperandOperations`
are merged to unify the processing of Designator in data clauses.

New code is added to unwrap the rightmost `evaluate::Component`, if any,
and remap it.

Note that when the right most part is an array reference on a component
(`obj%array(i:j:k)`), the whole component `obj%array(` is remapped, and
the array reference is dealt with a bound operand like for whole object
array.

After this patch, all designators in data clauses on structured
constructs will be remapped, except for array reference in private/first
private/reduction (the result type of the related operation needs to be
changed and the recipe adapted to "offset back"), component reference in
reduction (this patch is adding a TODO for it), and device_ptr
(previously bypassed remapping because of issues with descriptors,
should be OK to lift it in a further patch).

Note that this patch assumes that it is illegal to have code with
intermediate variable indexing in the component reference (e.g.
`array(i)%comp`) where the value of the index would be changed inside
the region (e.g., `i` is assigned a new value), or where the component
would be used with different indices meant to have the same value as the
one used in the clause (e.g. `array(i)%comp` where `j` is meant to be
the same as `i`). I will try to add a warning in semantics for such
questionable/risky usages.
2025-12-12 10:46:22 +01:00

167 lines
5.8 KiB
C++

//===-- SymbolMap.cpp -----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Pretty printers for symbol boxes, etc.
//
//===----------------------------------------------------------------------===//
#include "flang/Lower/SymbolMap.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "mlir/IR/BuiltinTypes.h"
#include "llvm/Support/Debug.h"
#include <optional>
#define DEBUG_TYPE "flang-lower-symbol-map"
void Fortran::lower::SymMap::addSymbol(Fortran::semantics::SymbolRef sym,
const fir::ExtendedValue &exv,
bool force) {
exv.match([&](const fir::UnboxedValue &v) { addSymbol(sym, v, force); },
[&](const fir::CharBoxValue &v) { makeSym(sym, v, force); },
[&](const fir::ArrayBoxValue &v) { makeSym(sym, v, force); },
[&](const fir::CharArrayBoxValue &v) { makeSym(sym, v, force); },
[&](const fir::BoxValue &v) { makeSym(sym, v, force); },
[&](const fir::MutableBoxValue &v) { makeSym(sym, v, force); },
[&](const fir::PolymorphicValue &v) { makeSym(sym, v, force); },
[](auto) {
llvm::report_fatal_error("value not added to symbol table");
});
}
Fortran::lower::SymbolBox
Fortran::lower::SymMap::lookupSymbol(Fortran::semantics::SymbolRef symRef) {
auto *sym = symRef->HasLocalLocality() ? &*symRef : &symRef->GetUltimate();
for (auto jmap = symbolMapStack.rbegin(), jend = symbolMapStack.rend();
jmap != jend; ++jmap) {
auto iter = jmap->find(sym);
if (iter != jmap->end())
return iter->second;
}
return SymbolBox::None{};
}
const Fortran::semantics::Symbol *
Fortran::lower::SymMap::lookupSymbolByName(llvm::StringRef symName) {
for (auto jmap = symbolMapStack.rbegin(), jend = symbolMapStack.rend();
jmap != jend; ++jmap)
for (auto const &[sym, symBox] : *jmap)
if (sym->name().ToString() == symName)
return sym;
return nullptr;
}
Fortran::lower::SymbolBox Fortran::lower::SymMap::shallowLookupSymbol(
Fortran::semantics::SymbolRef symRef) {
auto *sym = symRef->HasLocalLocality() ? &*symRef : &symRef->GetUltimate();
auto &map = symbolMapStack.back();
auto iter = map.find(sym);
if (iter != map.end())
return iter->second;
return SymbolBox::None{};
}
/// Skip one level when looking up the symbol. The use case is such as looking
/// up the host variable symbol box by skipping the associated level in
/// host-association in OpenMP code.
Fortran::lower::SymbolBox Fortran::lower::SymMap::lookupOneLevelUpSymbol(
Fortran::semantics::SymbolRef symRef) {
auto *sym = symRef->HasLocalLocality() ? &*symRef : &symRef->GetUltimate();
auto jmap = symbolMapStack.rbegin();
auto jend = symbolMapStack.rend();
if (jmap == jend)
return SymbolBox::None{};
// Skip one level in symbol map stack.
for (++jmap; jmap != jend; ++jmap) {
auto iter = jmap->find(sym);
if (iter != jmap->end())
return iter->second;
}
return SymbolBox::None{};
}
mlir::Value
Fortran::lower::SymMap::lookupImpliedDo(Fortran::lower::SymMap::AcDoVar var) {
for (auto [marker, binding] : llvm::reverse(impliedDoStack))
if (var == marker)
return binding;
return {};
}
void Fortran::lower::SymMap::registerStorage(
semantics::SymbolRef symRef, Fortran::lower::SymMap::StorageDesc storage) {
auto *sym = symRef->HasLocalLocality() ? &*symRef : &symRef->GetUltimate();
assert(storage.first && "registerting storage without an address");
storageMapStack.back().insert_or_assign(sym, std::move(storage));
}
Fortran::lower::SymMap::StorageDesc
Fortran::lower::SymMap::lookupStorage(Fortran::semantics::SymbolRef symRef) {
auto *sym = symRef->HasLocalLocality() ? &*symRef : &symRef->GetUltimate();
auto &map = storageMapStack.back();
auto iter = map.find(sym);
if (iter != map.end())
return iter->second;
return {nullptr, 0};
}
void Fortran::lower::SymbolBox::dump() const { llvm::errs() << *this << '\n'; }
void Fortran::lower::ComponentMap::dump() const {
llvm::errs() << "ComponentMap:\n";
for (const auto &entry : componentMap) {
const auto *component = entry.first;
llvm::errs() << " component @" << static_cast<const void *>(component)
<< " ->\n ";
llvm::errs() << entry.second << '\n';
}
}
void Fortran::lower::SymMap::dump() const { llvm::errs() << *this << '\n'; }
llvm::raw_ostream &
Fortran::lower::operator<<(llvm::raw_ostream &os,
const Fortran::lower::SymbolBox &symBox) {
symBox.match(
[&](const Fortran::lower::SymbolBox::None &box) {
os << "** symbol not properly mapped **\n";
},
[&](const Fortran::lower::SymbolBox::Intrinsic &val) {
os << val.getAddr() << '\n';
},
[&](const auto &box) { os << box << '\n'; });
return os;
}
llvm::raw_ostream &
Fortran::lower::operator<<(llvm::raw_ostream &os,
const Fortran::lower::SymMap &symMap) {
os << "Symbol map:\n";
for (auto i : llvm::enumerate(symMap.symbolMapStack)) {
os << " level " << i.index() << "<{\n";
for (auto iter : i.value()) {
os << " symbol @" << static_cast<const void *>(iter.first) << " ["
<< *iter.first << "] ->\n ";
os << iter.second;
}
os << " }>\n";
}
os << "Component map:\n";
for (auto i : llvm::enumerate(symMap.componentMapStack)) {
if (!i.value()) {
os << " level " << i.index() << "<{}>\n";
} else {
os << " level " << i.index() << "<{\n";
(*i.value())->dump();
os << " }>\n";
}
}
return os;
}