-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Reapply #91116 with fix #93160
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
Reapply #91116 with fix #93160
Conversation
@llvm/pr-subscribers-flang-openmp @llvm/pr-subscribers-flang-fir-hlfir Author: Kareem Ergawy (ergawy) ChangesThis PR contains 2 commits:
Patch is 138.31 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/93160.diff 61 Files Affected:
diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h
index 0bc68de6938da..f43dfd8343ece 100644
--- a/flang/include/flang/Lower/AbstractConverter.h
+++ b/flang/include/flang/Lower/AbstractConverter.h
@@ -131,7 +131,8 @@ class AbstractConverter {
/// For a given symbol, check if it is present in the inner-most
/// level of the symbol map.
- virtual bool isPresentShallowLookup(Fortran::semantics::Symbol &sym) = 0;
+ virtual bool
+ isPresentShallowLookup(const Fortran::semantics::Symbol &sym) = 0;
/// Collect the set of symbols with \p flag in \p eval
/// region if \p collectSymbols is true. Otherwise, collect the
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 898b37504a6e6..63ef60710ddfe 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -602,7 +602,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
return typeConstructionStack;
}
- bool isPresentShallowLookup(Fortran::semantics::Symbol &sym) override final {
+ bool
+ isPresentShallowLookup(const Fortran::semantics::Symbol &sym) override final {
return bool(shallowLookupSymbol(sym));
}
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
index 2bdc523bf3715..b722e19272ca1 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
@@ -22,6 +22,30 @@
namespace Fortran {
namespace lower {
namespace omp {
+bool DataSharingProcessor::OMPConstructSymbolVisitor::isSymbolDefineBy(
+ const semantics::Symbol *symbol, lower::pft::Evaluation &eval) const {
+ return eval.visit(
+ common::visitors{[&](const parser::OpenMPConstruct &functionParserNode) {
+ return symDefMap.count(symbol) &&
+ symDefMap.at(symbol) == &functionParserNode;
+ },
+ [](const auto &functionParserNode) { return false; }});
+}
+
+DataSharingProcessor::DataSharingProcessor(
+ lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
+ const List<Clause> &clauses, lower::pft::Evaluation &eval,
+ bool shouldCollectPreDeterminedSymbols, bool useDelayedPrivatization,
+ lower::SymMap *symTable)
+ : hasLastPrivateOp(false), converter(converter), semaCtx(semaCtx),
+ firOpBuilder(converter.getFirOpBuilder()), clauses(clauses), eval(eval),
+ shouldCollectPreDeterminedSymbols(shouldCollectPreDeterminedSymbols),
+ useDelayedPrivatization(useDelayedPrivatization), symTable(symTable),
+ visitor() {
+ eval.visit([&](const auto &functionParserNode) {
+ parser::Walk(functionParserNode, visitor);
+ });
+}
void DataSharingProcessor::processStep1(
mlir::omp::PrivateClauseOps *clauseOps,
@@ -29,9 +53,10 @@ void DataSharingProcessor::processStep1(
collectSymbolsForPrivatization();
collectDefaultSymbols();
collectImplicitSymbols();
+ collectPreDeterminedSymbols();
+
privatize(clauseOps, privateSyms);
- defaultPrivatize(clauseOps, privateSyms);
- implicitPrivatize(clauseOps, privateSyms);
+
insertBarrier();
}
@@ -57,7 +82,7 @@ void DataSharingProcessor::processStep2(mlir::Operation *op, bool isLoop) {
}
void DataSharingProcessor::insertDeallocs() {
- for (const semantics::Symbol *sym : privatizedSymbols)
+ for (const semantics::Symbol *sym : allPrivatizedSymbols)
if (semantics::IsAllocatable(sym->GetUltimate())) {
if (!useDelayedPrivatization) {
converter.createHostAssociateVarCloneDealloc(*sym);
@@ -92,10 +117,6 @@ void DataSharingProcessor::insertDeallocs() {
}
void DataSharingProcessor::cloneSymbol(const semantics::Symbol *sym) {
- // Privatization for symbols which are pre-determined (like loop index
- // variables) happen separately, for everything else privatize here.
- if (sym->test(semantics::Symbol::Flag::OmpPreDetermined))
- return;
bool success = converter.createHostAssociateVarClone(*sym);
(void)success;
assert(success && "Privatization failed due to existing binding");
@@ -126,20 +147,24 @@ void DataSharingProcessor::collectSymbolsForPrivatization() {
for (const omp::Clause &clause : clauses) {
if (const auto &privateClause =
std::get_if<omp::clause::Private>(&clause.u)) {
- collectOmpObjectListSymbol(privateClause->v, privatizedSymbols);
+ collectOmpObjectListSymbol(privateClause->v, explicitlyPrivatizedSymbols);
} else if (const auto &firstPrivateClause =
std::get_if<omp::clause::Firstprivate>(&clause.u)) {
- collectOmpObjectListSymbol(firstPrivateClause->v, privatizedSymbols);
+ collectOmpObjectListSymbol(firstPrivateClause->v,
+ explicitlyPrivatizedSymbols);
} else if (const auto &lastPrivateClause =
std::get_if<omp::clause::Lastprivate>(&clause.u)) {
const ObjectList &objects = std::get<ObjectList>(lastPrivateClause->t);
- collectOmpObjectListSymbol(objects, privatizedSymbols);
+ collectOmpObjectListSymbol(objects, explicitlyPrivatizedSymbols);
hasLastPrivateOp = true;
} else if (std::get_if<omp::clause::Collapse>(&clause.u)) {
hasCollapse = true;
}
}
+ for (auto *sym : explicitlyPrivatizedSymbols)
+ allPrivatizedSymbols.insert(sym);
+
if (hasCollapse && hasLastPrivateOp)
TODO(converter.getCurrentLocation(), "Collapse clause with lastprivate");
}
@@ -149,7 +174,7 @@ bool DataSharingProcessor::needBarrier() {
// initialization of firstprivate variables and post-update of lastprivate
// variables.
// Emit implicit barrier for linear clause. Maybe on somewhere else.
- for (const semantics::Symbol *sym : privatizedSymbols) {
+ for (const semantics::Symbol *sym : allPrivatizedSymbols) {
if (sym->test(semantics::Symbol::Flag::OmpFirstPrivate) &&
sym->test(semantics::Symbol::Flag::OmpLastPrivate))
return true;
@@ -283,10 +308,11 @@ void DataSharingProcessor::collectSymbolsInNestedRegions(
if (nestedEval.isConstruct())
// Recursively look for OpenMP constructs within `nestedEval`'s region
collectSymbolsInNestedRegions(nestedEval, flag, symbolsInNestedRegions);
- else
+ else {
converter.collectSymbolSet(nestedEval, symbolsInNestedRegions, flag,
/*collectSymbols=*/true,
/*collectHostAssociatedSymbols=*/false);
+ }
}
}
}
@@ -322,24 +348,44 @@ void DataSharingProcessor::collectSymbols(
converter.collectSymbolSet(eval, allSymbols, flag,
/*collectSymbols=*/true,
/*collectHostAssociatedSymbols=*/true);
+
llvm::SetVector<const semantics::Symbol *> symbolsInNestedRegions;
collectSymbolsInNestedRegions(eval, flag, symbolsInNestedRegions);
+
+ for (auto *symbol : allSymbols)
+ if (visitor.isSymbolDefineBy(symbol, eval))
+ symbolsInNestedRegions.remove(symbol);
+
// Filter-out symbols that must not be privatized.
bool collectImplicit = flag == semantics::Symbol::Flag::OmpImplicit;
+ bool collectPreDetermined = flag == semantics::Symbol::Flag::OmpPreDetermined;
+
auto isPrivatizable = [](const semantics::Symbol &sym) -> bool {
return !semantics::IsProcedure(sym) &&
!sym.GetUltimate().has<semantics::DerivedTypeDetails>() &&
!sym.GetUltimate().has<semantics::NamelistDetails>() &&
!semantics::IsImpliedDoIndex(sym.GetUltimate());
};
+
+ auto shouldCollectSymbol = [&](const semantics::Symbol *sym) {
+ if (collectImplicit)
+ return sym->test(semantics::Symbol::Flag::OmpImplicit);
+
+ if (collectPreDetermined)
+ return sym->test(semantics::Symbol::Flag::OmpPreDetermined);
+
+ return !sym->test(semantics::Symbol::Flag::OmpImplicit) &&
+ !sym->test(semantics::Symbol::Flag::OmpPreDetermined);
+ };
+
for (const auto *sym : allSymbols) {
assert(curScope && "couldn't find current scope");
if (isPrivatizable(*sym) && !symbolsInNestedRegions.contains(sym) &&
- !privatizedSymbols.contains(sym) &&
- !sym->test(semantics::Symbol::Flag::OmpPreDetermined) &&
- (collectImplicit || !sym->test(semantics::Symbol::Flag::OmpImplicit)) &&
- clauseScopes.contains(&sym->owner()))
+ !explicitlyPrivatizedSymbols.contains(sym) &&
+ shouldCollectSymbol(sym) && clauseScopes.contains(&sym->owner())) {
+ allPrivatizedSymbols.insert(sym);
symbols.insert(sym);
+ }
}
}
@@ -363,10 +409,16 @@ void DataSharingProcessor::collectImplicitSymbols() {
collectSymbols(semantics::Symbol::Flag::OmpImplicit, implicitSymbols);
}
+void DataSharingProcessor::collectPreDeterminedSymbols() {
+ if (shouldCollectPreDeterminedSymbols)
+ collectSymbols(semantics::Symbol::Flag::OmpPreDetermined,
+ preDeterminedSymbols);
+}
+
void DataSharingProcessor::privatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms) {
- for (const semantics::Symbol *sym : privatizedSymbols) {
+ for (const semantics::Symbol *sym : allPrivatizedSymbols) {
if (const auto *commonDet =
sym->detailsIf<semantics::CommonBlockDetails>()) {
for (const auto &mem : commonDet->objects())
@@ -378,7 +430,7 @@ void DataSharingProcessor::privatize(
void DataSharingProcessor::copyLastPrivatize(mlir::Operation *op) {
insertLastPrivateCompare(op);
- for (const semantics::Symbol *sym : privatizedSymbols)
+ for (const semantics::Symbol *sym : allPrivatizedSymbols)
if (const auto *commonDet =
sym->detailsIf<semantics::CommonBlockDetails>()) {
for (const auto &mem : commonDet->objects()) {
@@ -389,20 +441,6 @@ void DataSharingProcessor::copyLastPrivatize(mlir::Operation *op) {
}
}
-void DataSharingProcessor::defaultPrivatize(
- mlir::omp::PrivateClauseOps *clauseOps,
- llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms) {
- for (const semantics::Symbol *sym : defaultSymbols)
- doPrivatize(sym, clauseOps, privateSyms);
-}
-
-void DataSharingProcessor::implicitPrivatize(
- mlir::omp::PrivateClauseOps *clauseOps,
- llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms) {
- for (const semantics::Symbol *sym : implicitSymbols)
- doPrivatize(sym, clauseOps, privateSyms);
-}
-
void DataSharingProcessor::doPrivatize(
const semantics::Symbol *sym, mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms) {
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.h b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
index 111266eeb7848..5a95b295fa3c1 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.h
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
@@ -32,14 +32,46 @@ namespace omp {
class DataSharingProcessor {
private:
+ struct OMPConstructSymbolVisitor {
+ template <typename T>
+ bool Pre(const T &) {
+ return true;
+ }
+ template <typename T>
+ void Post(const T &) {}
+
+ bool Pre(const parser::OpenMPConstruct &omp) {
+ currentConstruct = &omp;
+ return true;
+ }
+
+ void Post(const parser::OpenMPConstruct &omp) {
+ currentConstruct = nullptr;
+ }
+
+ void Post(const parser::Name &name) {
+ symDefMap.try_emplace(name.symbol, currentConstruct);
+ }
+
+ const parser::OpenMPConstruct *currentConstruct = nullptr;
+ llvm::DenseMap<semantics::Symbol *, const parser::OpenMPConstruct *>
+ symDefMap;
+
+ bool isSymbolDefineBy(const semantics::Symbol *symbol,
+ lower::pft::Evaluation &eval) const;
+ };
+
bool hasLastPrivateOp;
mlir::OpBuilder::InsertPoint lastPrivIP;
mlir::OpBuilder::InsertPoint insPt;
mlir::Value loopIV;
// Symbols in private, firstprivate, and/or lastprivate clauses.
- llvm::SetVector<const semantics::Symbol *> privatizedSymbols;
+ llvm::SetVector<const semantics::Symbol *> explicitlyPrivatizedSymbols;
llvm::SetVector<const semantics::Symbol *> defaultSymbols;
llvm::SetVector<const semantics::Symbol *> implicitSymbols;
+ llvm::SetVector<const semantics::Symbol *> preDeterminedSymbols;
+ llvm::SetVector<const semantics::Symbol *> allPrivatizedSymbols;
+
llvm::DenseMap<const semantics::Symbol *, mlir::omp::PrivateClauseOp>
symToPrivatizer;
lower::AbstractConverter &converter;
@@ -47,8 +79,10 @@ class DataSharingProcessor {
fir::FirOpBuilder &firOpBuilder;
omp::List<omp::Clause> clauses;
lower::pft::Evaluation &eval;
+ bool shouldCollectPreDeterminedSymbols;
bool useDelayedPrivatization;
lower::SymMap *symTable;
+ OMPConstructSymbolVisitor visitor;
bool needBarrier();
void collectSymbols(semantics::Symbol::Flag flag,
@@ -63,6 +97,7 @@ class DataSharingProcessor {
void insertBarrier();
void collectDefaultSymbols();
void collectImplicitSymbols();
+ void collectPreDeterminedSymbols();
void privatize(mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms);
void defaultPrivatize(
@@ -90,11 +125,9 @@ class DataSharingProcessor {
semantics::SemanticsContext &semaCtx,
const List<Clause> &clauses,
lower::pft::Evaluation &eval,
+ bool shouldCollectPreDeterminedSymbols,
bool useDelayedPrivatization = false,
- lower::SymMap *symTable = nullptr)
- : hasLastPrivateOp(false), converter(converter), semaCtx(semaCtx),
- firOpBuilder(converter.getFirOpBuilder()), clauses(clauses), eval(eval),
- useDelayedPrivatization(useDelayedPrivatization), symTable(symTable) {}
+ lower::SymMap *symTable = nullptr);
// Privatisation is split into two steps.
// Step1 performs cloning of all privatisation clauses and copying for
diff --git a/flang/lib/Lower/OpenMP/Decomposer.cpp b/flang/lib/Lower/OpenMP/Decomposer.cpp
index e6897cb81e947..66e4028c7a287 100644
--- a/flang/lib/Lower/OpenMP/Decomposer.cpp
+++ b/flang/lib/Lower/OpenMP/Decomposer.cpp
@@ -123,4 +123,9 @@ ConstructQueue buildConstructQueue(
return constructs;
}
+
+bool isLastItemInQueue(ConstructQueue::iterator item,
+ const ConstructQueue &queue) {
+ return std::next(item) == queue.end();
+}
} // namespace Fortran::lower::omp
diff --git a/flang/lib/Lower/OpenMP/Decomposer.h b/flang/lib/Lower/OpenMP/Decomposer.h
index f42d8f5c17408..a7851d8534e54 100644
--- a/flang/lib/Lower/OpenMP/Decomposer.h
+++ b/flang/lib/Lower/OpenMP/Decomposer.h
@@ -46,6 +46,9 @@ ConstructQueue buildConstructQueue(mlir::ModuleOp modOp,
const parser::CharBlock &source,
llvm::omp::Directive compound,
const List<Clause> &clauses);
+
+bool isLastItemInQueue(ConstructQueue::iterator item,
+ const ConstructQueue &queue);
} // namespace Fortran::lower::omp
#endif // FORTRAN_LOWER_OPENMP_DECOMPOSER_H
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 1569605e785b0..9598457d123cf 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -215,12 +215,10 @@ createAndSetPrivatizedLoopVar(lower::AbstractConverter &converter,
firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock());
mlir::Type tempTy = converter.genType(*sym);
- mlir::Value temp = firOpBuilder.create<fir::AllocaOp>(
- loc, tempTy, /*pinned=*/true, /*lengthParams=*/mlir::ValueRange{},
- /*shapeParams*/ mlir::ValueRange{},
- llvm::ArrayRef<mlir::NamedAttribute>{
- fir::getAdaptToByRefAttr(firOpBuilder)});
- converter.bindSymbol(*sym, temp);
+
+ assert(converter.isPresentShallowLookup(*sym) &&
+ "Expected symbol to be in symbol table.");
+
firOpBuilder.restoreInsertionPoint(insPt);
mlir::Value cvtVal = firOpBuilder.createConvert(loc, tempTy, indexVal);
mlir::Operation *storeOp = firOpBuilder.create<fir::StoreOp>(
@@ -580,7 +578,8 @@ static void createBodyOfOp(mlir::Operation &op, const OpWithBodyGenInfo &info,
std::optional<DataSharingProcessor> tempDsp;
if (privatize) {
if (!info.dsp) {
- tempDsp.emplace(info.converter, info.semaCtx, *info.clauses, info.eval);
+ tempDsp.emplace(info.converter, info.semaCtx, *info.clauses, info.eval,
+ Fortran::lower::omp::isLastItemInQueue(item, queue));
tempDsp->processStep1();
}
}
@@ -1316,6 +1315,7 @@ genParallelOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
bool privatize = !outerCombined;
DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval,
+ lower::omp::isLastItemInQueue(item, queue),
/*useDelayedPrivatization=*/true, &symTable);
if (privatize)
@@ -1388,7 +1388,8 @@ genSectionsOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
// Insert privatizations before SECTIONS
symTable.pushScope();
- DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval);
+ DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval,
+ lower::omp::isLastItemInQueue(item, queue));
dsp.processStep1();
List<Clause> nonDsaClauses;
@@ -1458,7 +1459,9 @@ genSimdOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
mlir::Location loc, const ConstructQueue &queue,
ConstructQueue::iterator item) {
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
- DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval);
+ symTable.pushScope();
+ DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval,
+ lower::omp::isLastItemInQueue(item, queue));
dsp.processStep1();
lower::StatementContext stmtCtx;
@@ -1496,6 +1499,7 @@ genSimdOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
.setGenRegionEntryCb(ivCallback),
queue, item);
+ symTable.popScope();
return simdOp;
}
@@ -1764,7 +1768,9 @@ genWsloopOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
mlir::Location loc, const ConstructQueue &queue,
ConstructQueue::iterator item) {
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
- DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval);
+ symTable.pushScope();
+ DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval,
+ lower::omp::isLastItemInQueue(item, queue));
dsp.processStep1();
lower::StatementContext stmtCtx;
@@ -1807,6 +1813,7 @@ genWsloopOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
.setReductions(&reductionSyms, &reductionTypes)
.setGenRegionEntryCb(ivCallback),
queue, item);
+ symTable.popScope();
return wsloopOp;
}
diff --git a/flang/test/Lower/OpenMP/Todo/omp-default-clause-inner-loop.f90 b/flang/test/Lower/OpenMP/Todo/omp-default-clause-inner-loop.f90
index c245137f16c7a..773452206993f 100644
--- a/flang/test/Lower/OpenMP/Todo/omp-default-clause-inner-loop.f90
+++ b/flang/test/Lower/OpenMP/Todo/omp-default-clause-inner-loop.f90
@@ -8,7 +8,7 @@
! CHECK: omp.parallel {
! EXPECTED: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFEy"}
! EXPECTED: %[[PRIVATE_Z:.*]] = fir.alloca i32 {bindc_name = "z", pinned, uniq_name = "_QFEz"}
-! CHECK: %[[TEMP:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
+! CHECK: %[[TEMP:.*]] = fir.alloca i32 {bindc_name = "x", pinned, {{.*}}}
! CHECK: %[[const_1:.*]] = arith.constant 1 : i32
! CHECK: %[[const_2:.*]] = arith.constant 10 : i32
! CHECK: %[[const_3:.*]] = arith.constant 1 : i32
diff --git a/flang/test/Lower/OpenMP/copyin.f90 b/flang/test/Lower/OpenMP/copyin.f90
index dda563303148b..34c83fca46417 100644
--- a/flang/test/Lower/OpenMP/copyin.f90
+++ b/flang/test/Lower/OpenMP/copyin.f90
@@ -146,13 +146,17 @@ subroutine copyin_derived_type()
! CHECK: %[[VAL_4:.*]] = omp.threadprivate %[[VAL_3]]#1 : !fir.ref<i32> -> !fir.ref<i32>
! CHE...
[truncated]
|
… OMP regions. (llvm#91116)" This reapplies the referenced PR after finding a fix for the previously failing test suite tests.
4b5cfe3
to
efc37fe
Compare
Ping! 🔔 I tested this with the llvm-test-suite and now it passes all tests. Please take a look and let me know if you have any concerns with merging this PR! |
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.
LGTM. Thanks for this. I'm okay with the approach of having a custom symbol visitor to differentiate between DEF and REF, and then using it to modify symbolsInNestedRegion
.
Such a symbol visitor could be a useful tool later on, and maybe we can eventually move it into Utils.cpp
to share across different components. For now however, I think we can go ahead with the PR.
Feel free to go ahead. Could you change the summary to actually reflect what is being changed or introduced here? |
This PR contains 2 commits: