diff --git a/flang/include/flang/Lower/SymbolMap.h b/flang/include/flang/Lower/SymbolMap.h index a55e4b133fe0a8..6c90a0ccc7e99b 100644 --- a/flang/include/flang/Lower/SymbolMap.h +++ b/flang/include/flang/Lower/SymbolMap.h @@ -15,6 +15,7 @@ #include "flang/Common/reference.h" #include "flang/Optimizer/Builder/BoxValue.h" +#include "flang/Optimizer/Builder/VariableShadow.h" #include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/Dialect/FortranVariableInterface.h" #include "flang/Optimizer/Support/Matcher.h" @@ -77,7 +78,8 @@ struct SymbolBox : public fir::details::matcher { using VT = std::variant; + Box, fir::FortranVariableOpInterface, + hlfir::FortranVariableShadow, None>; //===--------------------------------------------------------------------===// // Constructors @@ -97,11 +99,13 @@ struct SymbolBox : public fir::details::matcher { /// scalar. For an array, this is the address of the first element in the /// array, etc. mlir::Value getAddr() const { - return match([](const None &) { return mlir::Value{}; }, - [](const fir::FortranVariableOpInterface &x) { - return fir::FortranVariableOpInterface(x).getBase(); - }, - [](const auto &x) { return x.getAddr(); }); + return match( + [](const None &) { return mlir::Value{}; }, + [](const fir::FortranVariableOpInterface &x) { + return fir::FortranVariableOpInterface(x).getBase(); + }, + [](const hlfir::FortranVariableShadow &x) { return x.getBase(); }, + [](const auto &x) { return x.getAddr(); }); } std::optional diff --git a/flang/include/flang/Optimizer/Builder/BoxValue.h b/flang/include/flang/Optimizer/Builder/BoxValue.h index 2fed2d48a7a080..151a197cc29b7f 100644 --- a/flang/include/flang/Optimizer/Builder/BoxValue.h +++ b/flang/include/flang/Optimizer/Builder/BoxValue.h @@ -13,6 +13,8 @@ #ifndef FORTRAN_OPTIMIZER_BUILDER_BOXVALUE_H #define FORTRAN_OPTIMIZER_BUILDER_BOXVALUE_H +#include "flang/Optimizer/Builder/Todo.h" +#include "flang/Optimizer/Builder/VariableShadow.h" #include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/Support/FatalError.h" #include "flang/Optimizer/Support/Matcher.h" @@ -479,7 +481,8 @@ class ExtendedValue : public details::matcher { public: using VT = std::variant; + ProcBoxValue, BoxValue, MutableBoxValue, PolymorphicValue, + hlfir::FortranVariableShadow>; ExtendedValue() : box{UnboxedValue{}} {} template { [](const fir::CharBoxValue &box) -> unsigned { return 0; }, [](const fir::ProcBoxValue &box) -> unsigned { return 0; }, [](const fir::PolymorphicValue &box) -> unsigned { return 0; }, + [](const hlfir::FortranVariableShadow &box) -> unsigned { + TODO(box.getValue().getLoc(), + "rank(): FortranVariableShadow"); + return 0; + }, [](const auto &box) -> unsigned { return box.rank(); }); } diff --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h index 170e134baef614..1de6e6b2d340da 100644 --- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h +++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h @@ -14,6 +14,7 @@ #define FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H #include "flang/Optimizer/Builder/BoxValue.h" +#include "flang/Optimizer/Builder/VariableShadow.h" #include "flang/Optimizer/Dialect/FIROps.h" #include "flang/Optimizer/Dialect/FortranVariableInterface.h" #include "flang/Optimizer/HLFIR/HLFIRDialect.h" @@ -55,8 +56,12 @@ class Entity : public mlir::Value { } Entity(fir::FortranVariableOpInterface variable) : mlir::Value(variable.getBase()) {} + Entity(FortranVariableShadow variableShadow) + : mlir::Value(variableShadow.getValue()) {} + bool isValue() const { return isFortranValue(*this); } bool isVariable() const { return !isValue(); } + bool isMutableShadow() const; bool isMutableBox() const { return hlfir::isBoxAddressType(getType()); } bool isProcedurePointer() const { return fir::isBoxProcAddressType(getType()); @@ -74,6 +79,10 @@ class Entity : public mlir::Value { /// Is this an assumed ranked entity? bool isAssumedRank() const { return getRank() == -1; } + bool isFortranVariableShadow() const { + return this->getType().isa(); + } + /// Return the rank of this entity or -1 if it is an assumed rank. int getRank() const { mlir::Type type = fir::unwrapPassByRefType(fir::unwrapRefType(getType())); @@ -152,6 +161,14 @@ class Entity : public mlir::Value { return this->getDefiningOp(); } + fir::ShadowType getIfVariableShadow() const { + fir::ExtractValueOp op = this->getDefiningOp(); + if (!op) + return fir::ShadowType(); + + return op.getAdt().getType().dyn_cast(); + } + // Return a "declaration" operation for this variable if visible, // or the "declaration" operation of the allocatable/pointer this // variable was dereferenced from (if it is visible). @@ -174,8 +191,13 @@ class Entity : public mlir::Value { } bool isAllocatable() const { - auto varIface = getIfVariableInterface(); - return varIface ? varIface.isAllocatable() : false; + if (auto varIface = getIfVariableInterface()) + return varIface.isAllocatable(); + + if (auto shadowType = getIfVariableShadow()) + return shadowType.getAllocatable(); + + return false; } bool isPointer() const { @@ -185,7 +207,7 @@ class Entity : public mlir::Value { // Get the entity as an mlir SSA value containing all the shape, type // parameters and dynamic shape information. - mlir::Value getBase() const { return *this; } + mlir::Value getBase() const; // Get the entity as a FIR base. This may not carry the shape and type // parameters information, and even when it is a box with shape information. @@ -231,6 +253,9 @@ translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, fir::ExtendedValue translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, fir::FortranVariableOpInterface fortranVariable); +fir::ExtendedValue +translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, + hlfir::FortranVariableShadow fortranVariableShadow); /// Generate declaration for a fir::ExtendedValue in memory. fir::FortranVariableOpInterface diff --git a/flang/include/flang/Optimizer/Builder/VariableShadow.h b/flang/include/flang/Optimizer/Builder/VariableShadow.h new file mode 100644 index 00000000000000..af83c4e34abb60 --- /dev/null +++ b/flang/include/flang/Optimizer/Builder/VariableShadow.h @@ -0,0 +1,47 @@ +//===-- VariableShadow.h ----------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Dialect/FortranVariableInterface.h" +#include "mlir/IR/Value.h" + +#ifndef FORTRAN_OPTIMIZER_BUILDER_VARIABLESHADOW_H +#define FORTRAN_OPTIMIZER_BUILDER_VARIABLESHADOW_H + +namespace hlfir { + +class FortranVariableShadow { +public: + FortranVariableShadow(fir::FirOpBuilder &builder, + mlir::BlockArgument shadowingVal, + fir::FortranVariableOpInterface shadowedVariable); + + mlir::BlockArgument getValue() const { return shadowingVal; } + + mlir::Value getBase() const { return base; } + + mlir::Value getFirBase() const { return firBase; } + + fir::FortranVariableOpInterface getShadowedVariable() const { + return shadowedVariable; + } + +private: + mlir::BlockArgument shadowingVal; + mlir::Value base; + mlir::Value firBase; + fir::FortranVariableOpInterface shadowedVariable; +}; + +} // namespace hlfir + +#endif // FORTRAN_OPTIMIZER_BUILDER_VARIABLESHADOW_H diff --git a/flang/include/flang/Optimizer/Dialect/FIRTypes.td b/flang/include/flang/Optimizer/Dialect/FIRTypes.td index 2a2f50720859e7..d83b216bce7b30 100644 --- a/flang/include/flang/Optimizer/Dialect/FIRTypes.td +++ b/flang/include/flang/Optimizer/Dialect/FIRTypes.td @@ -576,6 +576,65 @@ def fir_VoidType : FIR_Type<"Void", "void"> { let genStorageClass = 0; } +def fir_VariableShadowType : FIR_Type<"Shadow", "shadow"> { + let summary = "Type for Fortran-variables shadow values"; + + let description = [{ + A type to encapulate required data for a Fortran-variable shadow value. A + shadow type encapsulates the base type as well as the original base type. It + also encapsulates information other information about the shadowed value, + such as whether it is allocatable or not. + + For example, if we want to shadow a value produced a `hlfir.declare` + instruction similar to the following: + ``` + %1:2 = hlfir.declare %0 + {fortran_attrs = #fir.var_attrs} + : (!fir.ref>>) + -> (!fir.ref>>, !fir.ref>>) + ``` + + We would need to somehow create a value of the type: + ``` + !fir.shadow>>, + !fir.ref>>, + allocatable : true> + ``` + + The mechanism to create this value can be, for example, through a + combincation `fir.undefined`, `fir.insert_value` instructions similar to what + would be done for other composite types like `tuple`s: + ``` + %2 = fir.undefined !fir.shadow>>, + !fir.ref>>, + allocatable : true> + %3 = fir.insert_value %2, %1#0, [0 : index] : <... type info omitted ...> + %4 = fir.insert_value %3, %3#1, [1 : index] : <... type info omitted ...> + ``` + + From that point on, you can use `%4` as the shadow of the originally declared + variable being shadowed `%1`. + + For more info about the concept of variable shadows, check `VariableShadow.h`. + }]; + + let parameters = (ins "mlir::Type":$baseTy, + "mlir::Type":$firBaseTy, + "bool":$allocatable); + + let assemblyFormat = [{ + `<` $baseTy `,` $firBaseTy `,` `allocatable` `:` $allocatable `>` + }]; + + let extraClassDeclaration = [{ + mlir::Type getType(unsigned idx) const { + if (idx == 0) return getBaseTy(); + if (idx == 1) return getFirBaseTy(); + return mlir::Type(); + } + }]; +} + // Whether a type is a BaseBoxType def IsBaseBoxTypePred : CPred<"$_self.isa<::fir::BaseBoxType>()">; @@ -590,13 +649,17 @@ def AnyRealLike : TypeConstraint, "any real">; def AnyIntegerType : Type; +def IsShadowTypePred + : CPred<"$_self.isa<::fir::ShadowType>()">; + // Composable types // Note that we include both fir_ComplexType and AnyComplex, so we can use both // the FIR ComplexType and the MLIR ComplexType (the former is used to represent // Fortran complex and the latter for C++ std::complex). def AnyCompositeLike : TypeConstraint, + fir_VectorType.predicate, IsTupleTypePred, fir_CharacterType.predicate, + IsShadowTypePred]>, "any composite">; // Reference types diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 153ce0623ab3ae..3d2ff056aed650 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -468,6 +468,10 @@ class FirConverter : public Fortran::lower::AbstractConverter { return hlfir::translateToExtendedValue(getCurrentLocation(), getFirOpBuilder(), x); }, + [&](const hlfir::FortranVariableShadow &x) -> fir::ExtendedValue { + return hlfir::translateToExtendedValue(getCurrentLocation(), + getFirOpBuilder(), x); + }, [](const auto &box) -> fir::ExtendedValue { return box; }); } @@ -1009,6 +1013,16 @@ class FirConverter : public Fortran::lower::AbstractConverter { return v.match( [&](const Fortran::lower::SymbolBox::Intrinsic &) -> Fortran::lower::SymbolBox { return v; }, + [&](const hlfir::FortranVariableShadow &box) + -> Fortran::lower::SymbolBox { + auto exv = + hlfir::translateToExtendedValue(toLocation(), *builder, box); + return exv.match( + [](mlir::Value x) -> Fortran::lower::SymbolBox { + return Fortran::lower::SymbolBox::Intrinsic{x}; + }, + [](auto x) -> Fortran::lower::SymbolBox { return x; }); + }, [](const auto &) -> Fortran::lower::SymbolBox { return {}; }); return {}; @@ -1066,6 +1080,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { assert(lowerToHighLevelFIR()); hlfir::Entity lhs{dst}; hlfir::Entity rhs{src}; + // Temporary_lhs is set to true in hlfir.assign below to avoid user // assignment to be used and finalization to be called on the LHS. // This may or may not be correct but mimics the current behaviour diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp index d157db2cde4961..9b69bb10967349 100644 --- a/flang/lib/Lower/ConvertExpr.cpp +++ b/flang/lib/Lower/ConvertExpr.cpp @@ -981,6 +981,9 @@ class ScalarExprLowering { }, [&](const fir::ProcBoxValue &toBox) { TODO(loc, "procedure pointer component in derived type assignment"); + }, + [&](const hlfir::FortranVariableShadow &toBox) { + TODO(loc, "FortranVariableShadow in derived type assignment"); }); } return res; diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp index 717b8cc0276a30..be88d30e12d306 100644 --- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp +++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp @@ -15,7 +15,9 @@ #include "Utils.h" #include "flang/Lower/PFTBuilder.h" #include "flang/Lower/SymbolMap.h" +#include "flang/Optimizer/Builder/HLFIRTools.h" #include "flang/Optimizer/Builder/Todo.h" +#include "flang/Optimizer/HLFIR/HLFIROps.h" #include "flang/Semantics/tools.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" @@ -357,6 +359,28 @@ void DataSharingProcessor::doPrivatize(const Fortran::semantics::Symbol *sym) { bool isFirstPrivate = sym->test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate); + mlir::Type privatizerArgType = hsb.match( + [&](const fir::FortranVariableOpInterface &box) -> mlir::Type { + hlfir::Entity variable(box); + return fir::ShadowType::get( + &converter.getMLIRContext(), variable.getBase().getType(), + variable.getFirBase().getType(), variable.isAllocatable()); + }, + [&](const auto &box) -> mlir::Type { return symType; }); + + auto addSymbol = [&](mlir::Region ®ion, unsigned argIdx, bool force) { + hsb.match( + [&](const fir::FortranVariableOpInterface &box) { + hlfir::Entity variable(box); + hlfir::FortranVariableShadow variableShadow( + firOpBuilder, region.getArgument(argIdx), box); + symTable->addSymbol(*sym, variableShadow, force); + }, + [&](const auto &box) { + symTable->addSymbol(*sym, region.getArgument(argIdx), force); + }); + }; + mlir::omp::PrivateClauseOp privatizerOp = [&]() { auto moduleOp = firOpBuilder.getModule(); auto uniquePrivatizerName = fir::getTypeAsString( @@ -373,7 +397,7 @@ void DataSharingProcessor::doPrivatize(const Fortran::semantics::Symbol *sym) { firOpBuilder.setInsertionPoint(&moduleOp.getBodyRegion().front(), moduleOp.getBodyRegion().front().begin()); auto result = firOpBuilder.create( - symLoc, uniquePrivatizerName, symType, + symLoc, uniquePrivatizerName, privatizerArgType, isFirstPrivate ? mlir::omp::DataSharingClauseType::FirstPrivate : mlir::omp::DataSharingClauseType::Private); @@ -383,15 +407,44 @@ void DataSharingProcessor::doPrivatize(const Fortran::semantics::Symbol *sym) { { mlir::Region &allocRegion = result.getAllocRegion(); mlir::Block *allocEntryBlock = firOpBuilder.createBlock( - &allocRegion, /*insertPt=*/{}, symType, symLoc); + &allocRegion, /*insertPt=*/{}, privatizerArgType, symLoc); firOpBuilder.setInsertionPointToEnd(allocEntryBlock); - symTable->addSymbol(*sym, allocRegion.getArgument(0)); + addSymbol(allocRegion, 0, false); symTable->pushScope(); cloneSymbol(sym); - firOpBuilder.create( - hsb.getAddr().getLoc(), - symTable->shallowLookupSymbol(*sym).getAddr()); + + auto genYieldedVal = [&]() -> mlir::Value { + auto symBox = symTable->shallowLookupSymbol(*sym); + mlir::Value addr = symBox.getAddr(); + mlir::Operation *definingOp = addr.getDefiningOp(); + hlfir::DeclareOp declareOp = + mlir::dyn_cast(definingOp); + + if (declareOp == nullptr) { + return addr; + } + declareOp.getBase(); + declareOp.getOriginalBase(); + mlir::Location loc = declareOp.getLoc(); + + mlir::Value yieldTuple = + firOpBuilder.create(loc, privatizerArgType); + + mlir::Type idxTy = firOpBuilder.getIndexType(); + + yieldTuple = firOpBuilder.create( + loc, privatizerArgType, yieldTuple, declareOp.getBase(), + firOpBuilder.getArrayAttr({firOpBuilder.getIntegerAttr(idxTy, 0)})); + + yieldTuple = firOpBuilder.create( + loc, privatizerArgType, yieldTuple, declareOp.getOriginalBase(), + firOpBuilder.getArrayAttr({firOpBuilder.getIntegerAttr(idxTy, 1)})); + return yieldTuple; + }; + + firOpBuilder.create(hsb.getAddr().getLoc(), + genYieldedVal()); symTable->popScope(); } @@ -401,18 +454,19 @@ void DataSharingProcessor::doPrivatize(const Fortran::semantics::Symbol *sym) { // First block argument corresponding to the original/host value while // second block argument corresponding to the privatized value. mlir::Block *copyEntryBlock = firOpBuilder.createBlock( - ©Region, /*insertPt=*/{}, {symType, symType}, {symLoc, symLoc}); + ©Region, /*insertPt=*/{}, {privatizerArgType, privatizerArgType}, + {symLoc, symLoc}); firOpBuilder.setInsertionPointToEnd(copyEntryBlock); - symTable->addSymbol(*sym, copyRegion.getArgument(0), - /*force=*/true); + addSymbol(copyRegion, 0, true); + symTable->pushScope(); - symTable->addSymbol(*sym, copyRegion.getArgument(1)); + addSymbol(copyRegion, 1, false); + auto ip = firOpBuilder.saveInsertionPoint(); copyFirstPrivateSymbol(sym, &ip); - firOpBuilder.create( - hsb.getAddr().getLoc(), - symTable->shallowLookupSymbol(*sym).getAddr()); + firOpBuilder.create(hsb.getAddr().getLoc(), + copyRegion.getArgument(1)); symTable->popScope(); } @@ -423,7 +477,36 @@ void DataSharingProcessor::doPrivatize(const Fortran::semantics::Symbol *sym) { delayedPrivatizationInfo.privatizers.push_back( mlir::SymbolRefAttr::get(privatizerOp)); - delayedPrivatizationInfo.originalAddresses.push_back(hsb.getAddr()); + + hsb.match( + [&](const fir::FortranVariableOpInterface &box) { + mlir::Location loc = hsb.getAddr().getLoc(); + mlir::Operation *boxDefiningOp = + fir::FortranVariableOpInterface(box).getOperation(); + if (auto declareOp = mlir::dyn_cast(boxDefiningOp)) { + hlfir::Entity entity{box}; + mlir::Value originalTuple = + firOpBuilder.create(loc, privatizerArgType); + + mlir::Type idxTy = firOpBuilder.getIndexType(); + + originalTuple = firOpBuilder.create( + loc, privatizerArgType, originalTuple, entity.getBase(), + firOpBuilder.getArrayAttr( + {firOpBuilder.getIntegerAttr(idxTy, 0)})); + + originalTuple = firOpBuilder.create( + loc, privatizerArgType, originalTuple, entity.getFirBase(), + firOpBuilder.getArrayAttr( + {firOpBuilder.getIntegerAttr(idxTy, 1)})); + + delayedPrivatizationInfo.originalAddresses.push_back(originalTuple); + } else + TODO(loc, "Unsupported FortranVariableOpInterface operation."); + }, + [&](const auto &box) { + delayedPrivatizationInfo.originalAddresses.push_back(hsb.getAddr()); + }); delayedPrivatizationInfo.symbols.push_back(sym); } diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 83aebdaecd3504..ddb5a392919777 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -650,14 +650,31 @@ genParallelOp(Fortran::lower::AbstractConverter &converter, llvm::transform(privateVars, std::back_inserter(privateVarLocs), [](mlir::Value v) { return v.getLoc(); }); - converter.getFirOpBuilder().createBlock(®ion, /*insertPt=*/{}, - privateVarTypes, privateVarLocs); + auto &opBuilder = converter.getFirOpBuilder(); + opBuilder.createBlock(®ion, /*insertPt=*/{}, privateVarTypes, + privateVarLocs); llvm::SmallVector allSymbols = reductionSymbols; allSymbols.append(delayedPrivatizationInfo.symbols); for (auto [arg, prv] : llvm::zip_equal(allSymbols, region.getArguments())) { - converter.bindSymbol(*arg, prv); + // TODO Another place where a custom type would be more suitable. + bool isFortranVariableShadow = [](mlir::Value val) { + return val.getType().dyn_cast() != nullptr; + }(prv); + + if (isFortranVariableShadow) { + fir::ShadowType tupleType = prv.getType().cast(); + auto firBase = opBuilder + .create( + prv.getLoc(), tupleType.getType(1), prv, + opBuilder.getArrayAttr({opBuilder.getIntegerAttr( + opBuilder.getIndexType(), 1)})) + .getRes(); + converter.bindSymbol(*arg, firBase); + } else { + converter.bindSymbol(*arg, prv); + } } return allSymbols; diff --git a/flang/lib/Lower/SymbolMap.cpp b/flang/lib/Lower/SymbolMap.cpp index ce078a7fbde651..7c25447f2dae96 100644 --- a/flang/lib/Lower/SymbolMap.cpp +++ b/flang/lib/Lower/SymbolMap.cpp @@ -21,16 +21,18 @@ 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"); - }); + 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); }, + [&](const hlfir::FortranVariableShadow &v) { makeSym(sym, v, force); }, + [](auto) { + llvm::report_fatal_error("value not added to symbol table"); + }); } Fortran::lower::SymbolBox diff --git a/flang/lib/Optimizer/Builder/BoxValue.cpp b/flang/lib/Optimizer/Builder/BoxValue.cpp index 361fa59e204037..b383f476032fb9 100644 --- a/flang/lib/Optimizer/Builder/BoxValue.cpp +++ b/flang/lib/Optimizer/Builder/BoxValue.cpp @@ -19,8 +19,10 @@ #define DEBUG_TYPE "flang-box-value" mlir::Value fir::getBase(const fir::ExtendedValue &exv) { - return exv.match([](const fir::UnboxedValue &x) { return x; }, - [](const auto &x) { return x.getAddr(); }); + return exv.match( + [](const fir::UnboxedValue &x) { return x; }, + [](const hlfir::FortranVariableShadow &x) { return x.getBase(); }, + [](const auto &x) { return x.getAddr(); }); } mlir::Value fir::getLen(const fir::ExtendedValue &exv) { @@ -40,6 +42,11 @@ fir::ExtendedValue fir::substBase(const fir::ExtendedValue &exv, mlir::Value base) { return exv.match( [=](const fir::UnboxedValue &x) { return fir::ExtendedValue(base); }, + [=](const hlfir::FortranVariableShadow &x) { + [[maybe_unused]] auto loc = fir::getBase(exv).getLoc(); + TODO(loc, "substBase not supported for hlfir::FortranVariableShadow"); + return fir::ExtendedValue(); + }, [=](const auto &x) { return fir::ExtendedValue(x.clone(base)); }); } diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp index 4ffa303f27103a..e14fae68429750 100644 --- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp +++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp @@ -183,6 +183,36 @@ static fir::CharBoxValue genUnboxChar(mlir::Location loc, return {addr, len}; } +static bool checkIsIntegerConstant(mlir::Attribute attr, std::int64_t conVal) { + if (auto iattr = attr.dyn_cast()) + return iattr.getInt() == conVal; + return false; +} + +static bool isZero(mlir::Attribute a) { return checkIsIntegerConstant(a, 0); } +static bool isOne(mlir::Attribute a) { return checkIsIntegerConstant(a, 1); } + +bool hlfir::Entity::isMutableShadow() const { + if (!isFortranVariableShadow()) + return false; + + auto tupleType = getType().cast(); + return hlfir::isBoxAddressType(tupleType.getType(1)); +} + +mlir::Value hlfir::Entity::getBase() const { + if (isFortranVariableShadow()) { + for (auto *user : getUsers()) { + if (auto extractOp = mlir::dyn_cast(*user)) { + if (isZero(extractOp.getCoor()[0])) + return extractOp; + } + } + } + + return *this; +} + mlir::Value hlfir::Entity::getFirBase() const { if (fir::FortranVariableOpInterface variable = getIfVariableInterface()) { if (auto declareOp = @@ -192,9 +222,38 @@ mlir::Value hlfir::Entity::getFirBase() const { mlir::dyn_cast(variable.getOperation())) return associateOp.getFirBase(); } + + if (isFortranVariableShadow()) { + for (auto *user : getUsers()) { + if (auto extractOp = mlir::dyn_cast(*user)) { + if (isOne(extractOp.getCoor()[0])) { + return extractOp; + } + } + } + } + return getBase(); } +hlfir::FortranVariableShadow::FortranVariableShadow( + fir::FirOpBuilder &builder, mlir::BlockArgument shadowingVal, + fir::FortranVariableOpInterface shadowedVariable) + : shadowingVal(shadowingVal), shadowedVariable(shadowedVariable) { + fir::ShadowType shadowingValType = + shadowingVal.getType().cast(); + auto baseExtractor = [&](unsigned elementIdx) { + return builder.create( + shadowingVal.getLoc(), shadowingValType.getType(elementIdx), + shadowingVal, + builder.getArrayAttr( + {builder.getIntegerAttr(builder.getIndexType(), elementIdx)})); + }; + + base = baseExtractor(0); + firBase = baseExtractor(1); +} + fir::FortranVariableOpInterface hlfir::genDeclare(mlir::Location loc, fir::FirOpBuilder &builder, const fir::ExtendedValue &exv, llvm::StringRef name, @@ -853,9 +912,10 @@ translateVariableToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, /// When going towards FIR, use the original base value to avoid /// introducing descriptors at runtime when they are not required. mlir::Value firBase = variable.getFirBase(); - if (variable.isMutableBox()) + if (variable.isMutableBox() || variable.isMutableShadow()) { return fir::MutableBoxValue(firBase, getExplicitTypeParams(variable), fir::MutableProperties{}); + } if (firBase.getType().isa()) { if (!variable.isSimplyContiguous() || variable.isPolymorphic() || @@ -904,6 +964,12 @@ hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, return translateVariableToExtendedValue(loc, builder, var); } +fir::ExtendedValue +hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, + hlfir::FortranVariableShadow var) { + return translateVariableToExtendedValue(loc, builder, var); +} + std::pair> hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity entity) { diff --git a/flang/lib/Optimizer/Builder/MutableBox.cpp b/flang/lib/Optimizer/Builder/MutableBox.cpp index d4012e9c3d9d93..31f65e052db523 100644 --- a/flang/lib/Optimizer/Builder/MutableBox.cpp +++ b/flang/lib/Optimizer/Builder/MutableBox.cpp @@ -562,6 +562,9 @@ void fir::factory::associateMutableBox(fir::FirOpBuilder &builder, }, [&](const fir::ProcBoxValue &) { TODO(loc, "procedure pointer assignment"); + }, + [&](const hlfir::FortranVariableShadow &) { + TODO(loc, "FortranVariableShadow assignment"); }); } @@ -663,6 +666,9 @@ void fir::factory::associateMutableBoxWithRemap( }, [&](const fir::ProcBoxValue &) { TODO(loc, "procedure pointer assignment"); + }, + [&](const hlfir::FortranVariableShadow &) { + TODO(loc, "FortranVariableShadow assignment"); }); } diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp index 8a2c681d958609..0116bb614f62f3 100644 --- a/flang/lib/Optimizer/Dialect/FIRType.cpp +++ b/flang/lib/Optimizer/Dialect/FIRType.cpp @@ -1325,7 +1325,7 @@ void FIROpsDialect::registerTypes() { fir::ComplexType, FieldType, HeapType, fir::IntegerType, LenType, LogicalType, LLVMPointerType, PointerType, RealType, RecordType, ReferenceType, SequenceType, ShapeType, ShapeShiftType, ShiftType, - SliceType, TypeDescType, fir::VectorType>(); + SliceType, TypeDescType, fir::VectorType, fir::ShadowType>(); fir::ReferenceType::attachInterface< OpenMPPointerLikeModel>(*getContext()); fir::ReferenceType::attachInterface< diff --git a/flang/test/Lower/OpenMP/delayed-privatization-allocatable.f90 b/flang/test/Lower/OpenMP/delayed-privatization-allocatable.f90 new file mode 100644 index 00000000000000..9be12c162b4030 --- /dev/null +++ b/flang/test/Lower/OpenMP/delayed-privatization-allocatable.f90 @@ -0,0 +1,69 @@ +! Test delayed privatization for allocatables. + +! RUN: bbc -emit-hlfir -fopenmp --openmp-enable-delayed-privatization -o - %s 2>&1 | FileCheck %s + +subroutine delayed_privatization_allocatable + implicit none + integer, allocatable :: var1 + +!$omp parallel firstprivate(var1) + var1 = 10 +!$omp end parallel +end subroutine + +! CHECK-LABEL: omp.private {type = firstprivate} +! CHECK-SAME: @[[PRIVATIZER_SYM:.*]] : [[TYPE:!fir.shadow>>, !fir.ref>>, allocatable : true>]] alloc { + +! CHECK-NEXT: ^bb0(%[[PRIV_ARG:.*]]: [[TYPE]]): + +! CHECK-NEXT: %[[BASE:.*]] = fir.extract_value %[[PRIV_ARG]], [0 : index] : ([[TYPE]]) +! CHECK-NEXT: %[[FIR_BASE:.*]] = fir.extract_value %[[PRIV_ARG]], [1 : index] : ([[TYPE]]) + +! CHECK-NEXT: %[[PRIV_ALLOC:.*]] = fir.alloca !fir.box> {bindc_name = "var1", pinned, uniq_name = "_QFdelayed_privatization_allocatableEvar1"} + +! CHECK-NEXT: %[[FIR_BASE_VAL:.*]] = fir.load %[[FIR_BASE]] : !fir.ref>> +! CHECK-NEXT: %[[FIR_BASE_BOX:.*]] = fir.box_addr %[[FIR_BASE_VAL]] : (!fir.box>) -> !fir.heap +! CHECK-NEXT: %[[FIR_BASE_ADDR:.*]] = fir.convert %[[FIR_BASE_BOX]] : (!fir.heap) -> i64 +! CHECK-NEXT: %[[C0:.*]] = arith.constant 0 : i64 +! CHECK-NEXT: %[[ALLOC_COND:.*]] = arith.cmpi ne, %[[FIR_BASE_ADDR]], %[[C0]] : i64 + +! CHECK-NEXT: fir.if %[[ALLOC_COND]] { +! CHECK-NEXT: %[[PRIV_ALLOCMEM:.*]] = fir.allocmem i32 {fir.must_be_heap = true, uniq_name = "_QFdelayed_privatization_allocatableEvar1.alloc"} +! CHECK-NEXT: %[[PRIV_ALLOCMEM_BOX:.*]] = fir.embox %[[PRIV_ALLOCMEM]] : (!fir.heap) -> !fir.box> +! CHECK-NEXT: fir.store %[[PRIV_ALLOCMEM_BOX]] to %[[PRIV_ALLOC]] : !fir.ref>> +! CHECK-NEXT: } else { +! CHECK-NEXT: %[[ZERO_BITS:.*]] = fir.zero_bits !fir.heap +! CHECK-NEXT: %[[ZERO_BOX:.*]] = fir.embox %[[ZERO_BITS]] : (!fir.heap) -> !fir.box> +! CHECK-NEXT: fir.store %[[ZERO_BOX]] to %[[PRIV_ALLOC]] : !fir.ref>> +! CHECK-NEXT: } + +! CHECK-NEXT: %[[PRIV_DECL:.*]]:2 = hlfir.declare %[[PRIV_ALLOC]] + +! CHECK-NEXT: %[[PRIV_SHADOW:.*]] = fir.undefined [[TYPE]] +! CHECK-NEXT: %[[PRIV_SHADOW_2:.*]] = fir.insert_value %[[PRIV_SHADOW]], %[[PRIV_DECL]]#0, [0 : index] +! CHECK-NEXT: %[[PRIV_SHADOW_3:.*]] = fir.insert_value %[[PRIV_SHADOW_2]], %[[PRIV_DECL]]#1, [1 : index] + +! CHECK-NEXT: omp.yield(%[[PRIV_SHADOW_3]] : [[TYPE]]) + +! CHECK-NEXT: } copy { +! CHECK: ^bb0(%[[PRIV_ORIG_ARG:.*]]: [[TYPE]], %[[PRIV_PRIV_ARG:.*]]: [[TYPE]]): +! CHECK-NEXT: %[[ORIG_BASE:.*]] = fir.extract_value %[[PRIV_ORIG_ARG]], [0 : index] : ([[TYPE]]) +! CHECK-NEXT: %[[ORIG_FIR_BASE:.*]] = fir.extract_value %[[PRIV_ORIG_ARG]], [1 : index] : ([[TYPE]]) + +! CHECK-NEXT: %[[PRIV_BASE:.*]] = fir.extract_value %[[PRIV_PRIV_ARG]], [0 : index] : ([[TYPE]]) +! CHECK-NEXT: %[[PRIV_FIR_BASE:.*]] = fir.extract_value %[[PRIV_PRIV_ARG]], [1 : index] : ([[TYPE]]) + +! CHECK-NEXT: %[[PRIV_BASE_VAL:.*]] = fir.load %[[PRIV_BASE]] +! CHECK-NEXT: %[[PRIV_BASE_BOX:.*]] = fir.box_addr %[[PRIV_BASE_VAL]] +! CHECK-NEXT: %[[PRIV_BASE_ADDR:.*]] = fir.convert %[[PRIV_BASE_BOX]] +! CHECK-NEXT: %[[C0:.*]] = arith.constant 0 : i64 +! CHECK-NEXT: %[[COPY_COND:.*]] = arith.cmpi ne, %[[PRIV_BASE_ADDR]], %[[C0]] : i64 + +! CHECK-NEXT: fir.if %[[COPY_COND]] { +! CHECK-NEXT: %[[ORIG_BASE_VAL:.*]] = fir.load %[[ORIG_BASE]] +! CHECK-NEXT: %[[ORIG_BASE_ADDR:.*]] = fir.box_addr %[[ORIG_BASE_VAL]] +! CHECK-NEXT: %[[ORIG_BASE_LD:.*]] = fir.load %[[ORIG_BASE_ADDR]] +! CHECK-NEXT: hlfir.assign %[[ORIG_BASE_LD]] to %[[PRIV_BASE_BOX]] temporary_lhs +! CHECK-NEXT: } + +! CHECK-NEXT: omp.yield(%[[PRIV_PRIV_ARG]] : [[TYPE]]) diff --git a/flang/test/Lower/OpenMP/delayed-privatization-firstprivate.f90 b/flang/test/Lower/OpenMP/delayed-privatization-firstprivate.f90 index e3d2a5a8af2608..d83df6c334f838 100644 --- a/flang/test/Lower/OpenMP/delayed-privatization-firstprivate.f90 +++ b/flang/test/Lower/OpenMP/delayed-privatization-firstprivate.f90 @@ -12,18 +12,34 @@ subroutine delayed_privatization_firstprivate end subroutine ! CHECK-LABEL: omp.private {type = firstprivate} -! CHECK-SAME: @[[VAR1_PRIVATIZER_SYM:.*]] : !fir.ref alloc { -! CHECK-NEXT: ^bb0(%[[PRIV_ARG:.*]]: !fir.ref): +! CHECK-SAME: @[[PRIVATIZER_SYM:.*]] : [[TYPE:!fir.shadow, !fir.ref, allocatable : false>]] alloc { +! CHECK-NEXT: ^bb0(%[[PRIV_ARG:.*]]: [[TYPE]]): + +! CHECK-NEXT: %[[BASE:.*]] = fir.extract_value %[[PRIV_ARG]], [0 : index] : ([[TYPE]]) -> !fir.ref +! CHECK-NEXT: %[[FIR_BASE:.*]] = fir.extract_value %[[PRIV_ARG]], [1 : index] : ([[TYPE]]) -> !fir.ref + ! CHECK-NEXT: %[[PRIV_ALLOC:.*]] = fir.alloca i32 {bindc_name = "var1", pinned, uniq_name = "_QFdelayed_privatization_firstprivateEvar1"} ! CHECK-NEXT: %[[PRIV_DECL:.*]]:2 = hlfir.declare %[[PRIV_ALLOC]] {uniq_name = "_QFdelayed_privatization_firstprivateEvar1"} : (!fir.ref) -> (!fir.ref, !fir.ref) -! CHECK-NEXT: omp.yield(%[[PRIV_DECL]]#0 : !fir.ref) + +! CHECK-NEXT: %[[YIELD_VAL:.*]] = fir.undefined [[TYPE]] +! CHECK-NEXT: %[[YIELD_VAL_2:.*]] = fir.insert_value %[[YIELD_VAL]], %[[PRIV_DECL]]#0, [0 : index] : ([[TYPE]], !fir.ref) -> [[TYPE]] +! CHECK-NEXT: %[[YIELD_VAL_3:.*]] = fir.insert_value %[[YIELD_VAL_2]], %[[PRIV_DECL]]#1, [1 : index] : ([[TYPE]], !fir.ref) -> [[TYPE]] + +! CHECK-NEXT: omp.yield(%[[YIELD_VAL_3]] : [[TYPE]]) + ! CHECK: } copy { -! CHECK: ^bb0(%[[PRIV_ORIG_ARG:.*]]: !fir.ref, %[[PRIV_PRIV_ARG:.*]]: !fir.ref): -! CHECK: %[[ORIG_VAL:.*]] = fir.load %[[PRIV_ORIG_ARG]] : !fir.ref -! CHECK: hlfir.assign %[[ORIG_VAL]] to %[[PRIV_PRIV_ARG]] temporary_lhs : i32, !fir.ref -! CHECK: omp.yield(%[[PRIV_PRIV_ARG]] : !fir.ref) -! CHECK: } +! CHECK: ^bb0(%[[PRIV_ORIG_ARG:.*]]: [[TYPE]], %[[PRIV_PRIV_ARG:.*]]: [[TYPE]]): + +! CHECK-NEXT: %[[ORIG_BASE:.*]] = fir.extract_value %[[PRIV_ORIG_ARG]], [0 : index] : ([[TYPE]]) -> !fir.ref +! CHECK-NEXT: %[[ORIG_FIR_BASE:.*]] = fir.extract_value %[[PRIV_ORIG_ARG]], [1 : index] : ([[TYPE]]) -> !fir.ref + +! CHECK-NEXT: %[[PRIV_BASE:.*]] = fir.extract_value %[[PRIV_PRIV_ARG]], [0 : index] : ([[TYPE]]) -> !fir.ref +! CHECK-NEXT: %[[PRIV_FIR_BASE:.*]] = fir.extract_value %[[PRIV_PRIV_ARG]], [1 : index] : ([[TYPE]]) -> !fir.ref + +! CHECK-NEXT: %[[ORIG_VAL:.*]] = fir.load %[[ORIG_BASE]] : !fir.ref +! CHECK-NEXT: hlfir.assign %[[ORIG_VAL]] to %[[PRIV_BASE]] temporary_lhs : i32, !fir.ref +! CHECK-NEXT: omp.yield(%[[PRIV_PRIV_ARG]] : [[TYPE]]) ! CHECK-LABEL: @_QPdelayed_privatization_firstprivate -! CHECK: omp.parallel private(@[[VAR1_PRIVATIZER_SYM]] %{{.*}} -> %{{.*}} : !fir.ref) { +! CHECK: omp.parallel private(@[[PRIVATIZER_SYM]] %{{.*}} -> %{{.*}} : [[TYPE]]) { ! CHECK: omp.terminator diff --git a/flang/test/Lower/OpenMP/delayed-privatization-private-firstprivate.f90 b/flang/test/Lower/OpenMP/delayed-privatization-private-firstprivate.f90 index 46eef6eb3bcf6a..d528004df27c93 100644 --- a/flang/test/Lower/OpenMP/delayed-privatization-private-firstprivate.f90 +++ b/flang/test/Lower/OpenMP/delayed-privatization-private-firstprivate.f90 @@ -14,12 +14,12 @@ subroutine delayed_privatization_private_firstprivate end subroutine ! CHECK-LABEL: omp.private {type = firstprivate} -! CHECK-SAME: @[[VAR2_PRIVATIZER_SYM:.*]] : !fir.ref alloc { +! CHECK-SAME: @[[VAR2_PRIVATIZER_SYM:.*]] : [[TYPE:!fir.shadow, !fir.ref, allocatable : false>]] alloc { ! CHECK: } copy { ! CHECK: } ! CHECK-LABEL: omp.private {type = private} -! CHECK-SAME: @[[VAR1_PRIVATIZER_SYM:.*]] : !fir.ref alloc { +! CHECK-SAME: @[[VAR1_PRIVATIZER_SYM:.*]] : [[TYPE]] alloc { ! CHECK: } ! CHECK-LABEL: func.func @_QPdelayed_privatization_private_firstprivate() { @@ -29,6 +29,14 @@ subroutine delayed_privatization_private_firstprivate ! CHECK: %[[VAR2_ALLOC:.*]] = fir.alloca i32 {bindc_name = "var2" ! CHECK: %[[VAR2_DECL:.*]]:2 = hlfir.declare %[[VAR2_ALLOC]] +! CHECK: %[[VAR1_VAL:.*]] = fir.undefined [[TYPE]] +! CHECK: %[[VAR1_VAL_2:.*]] = fir.insert_value %[[VAR1_VAL]], %[[VAR1_DECL]]#0, [0 : index] +! CHECK: %[[VAR1_VAL_3:.*]] = fir.insert_value %[[VAR1_VAL_2]], %[[VAR1_DECL]]#1, [1 : index] + +! CHECK: %[[VAR2_VAL:.*]] = fir.undefined [[TYPE]] +! CHECK: %[[VAR2_VAL_2:.*]] = fir.insert_value %[[VAR2_VAL]], %[[VAR2_DECL]]#0, [0 : index] +! CHECK: %[[VAR2_VAL_3:.*]] = fir.insert_value %[[VAR2_VAL_2]], %[[VAR2_DECL]]#1, [1 : index] + ! CHECK: omp.parallel private( -! CHECK-SAME: @[[VAR1_PRIVATIZER_SYM]] %[[VAR1_DECL]]#0 -> %{{.*}} : !fir.ref, -! CHECK-SAME: @[[VAR2_PRIVATIZER_SYM]] %[[VAR2_DECL]]#0 -> %{{.*}} : !fir.ref) { +! CHECK-SAME: @[[VAR1_PRIVATIZER_SYM]] %[[VAR1_VAL_3]] -> %{{.*}} : [[TYPE]], +! CHECK-SAME: @[[VAR2_PRIVATIZER_SYM]] %[[VAR2_VAL_3]] -> %{{.*}} : [[TYPE]]) { diff --git a/flang/test/Lower/OpenMP/delayed-privatization-private.f90 b/flang/test/Lower/OpenMP/delayed-privatization-private.f90 index 240e0e71bfcd16..02cc5d307a794a 100644 --- a/flang/test/Lower/OpenMP/delayed-privatization-private.f90 +++ b/flang/test/Lower/OpenMP/delayed-privatization-private.f90 @@ -12,17 +12,32 @@ subroutine delayed_privatization_private end subroutine ! CHECK-LABEL: omp.private {type = private} -! CHECK-SAME: @[[PRIVATIZER_SYM:.*]] : !fir.ref alloc { -! CHECK-NEXT: ^bb0(%[[PRIV_ARG:.*]]: !fir.ref): +! CHECK-SAME: @[[PRIVATIZER_SYM:.*]] : [[TYPE:!fir.shadow, !fir.ref, allocatable : false>]] alloc { +! CHECK-NEXT: ^bb0(%[[PRIV_ARG:.*]]: [[TYPE]]): + +! CHECK-NEXT: %[[BASE:.*]] = fir.extract_value %[[PRIV_ARG]], [0 : index] : ([[TYPE]]) -> !fir.ref +! CHECK-NEXT: %[[FIR_BASE:.*]] = fir.extract_value %[[PRIV_ARG]], [1 : index] : ([[TYPE]]) -> !fir.ref + ! CHECK-NEXT: %[[PRIV_ALLOC:.*]] = fir.alloca i32 {bindc_name = "var1", pinned, uniq_name = "_QFdelayed_privatization_privateEvar1"} ! CHECK-NEXT: %[[PRIV_DECL:.*]]:2 = hlfir.declare %[[PRIV_ALLOC]] {uniq_name = "_QFdelayed_privatization_privateEvar1"} : (!fir.ref) -> (!fir.ref, !fir.ref) -! CHECK-NEXT: omp.yield(%[[PRIV_DECL]]#0 : !fir.ref) + +! CHECK-NEXT: %[[YIELD_VAL:.*]] = fir.undefined [[TYPE]] +! CHECK-NEXT: %[[YIELD_VAL_2:.*]] = fir.insert_value %[[YIELD_VAL]], %[[PRIV_DECL]]#0, [0 : index] : ([[TYPE]], !fir.ref) -> [[TYPE]] +! CHECK-NEXT: %[[YIELD_VAL_3:.*]] = fir.insert_value %[[YIELD_VAL_2]], %[[PRIV_DECL]]#1, [1 : index] : ([[TYPE]], !fir.ref) -> [[TYPE]] + +! CHECK-NEXT: omp.yield(%[[YIELD_VAL_3]] : [[TYPE]]) ! CHECK-NOT: } copy { ! CHECK-LABEL: @_QPdelayed_privatization_private ! CHECK: %[[ORIG_ALLOC:.*]] = fir.alloca i32 {bindc_name = "var1", uniq_name = "_QFdelayed_privatization_privateEvar1"} ! CHECK: %[[ORIG_DECL:.*]]:2 = hlfir.declare %[[ORIG_ALLOC]] {uniq_name = "_QFdelayed_privatization_privateEvar1"} : (!fir.ref) -> (!fir.ref, !fir.ref) -! CHECK: omp.parallel private(@[[PRIVATIZER_SYM]] %[[ORIG_DECL]]#0 -> %[[PAR_ARG:.*]] : !fir.ref) { -! CHECK: %[[PAR_ARG_DECL:.*]]:2 = hlfir.declare %[[PAR_ARG]] {uniq_name = "_QFdelayed_privatization_privateEvar1"} : (!fir.ref) -> (!fir.ref, !fir.ref) + +! CHECK-NEXT: %[[ORIG_VAL:.*]] = fir.undefined [[TYPE]] +! CHECK-NEXT: %[[ORIG_VAL_2:.*]] = fir.insert_value %[[ORIG_VAL]], %[[ORIG_DECL]]#0, [0 : index] : ([[TYPE]], !fir.ref) -> [[TYPE]] +! CHECK-NEXT: %[[ORIG_VAL_3:.*]] = fir.insert_value %[[ORIG_VAL_2]], %[[ORIG_DECL]]#1, [1 : index] : ([[TYPE]], !fir.ref) -> [[TYPE]] + +! CHECK: omp.parallel private(@[[PRIVATIZER_SYM]] %[[ORIG_VAL_3]] -> %[[PAR_ARG:.*]] : [[TYPE]]) { +! CHECK: %[[PAR_ARG_FIR_BASE:.*]] = fir.extract_value %[[PAR_ARG]], [1 : index] : ([[TYPE]]) -> !fir.ref +! CHECK: %[[PAR_ARG_DECL:.*]]:2 = hlfir.declare %[[PAR_ARG_FIR_BASE]] {uniq_name = "_QFdelayed_privatization_privateEvar1"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: hlfir.assign %{{.*}} to %[[PAR_ARG_DECL]]#0 : i32, !fir.ref ! CHECK: omp.terminator diff --git a/flang/test/Lower/OpenMP/delayed-privatization-reduction.f90 b/flang/test/Lower/OpenMP/delayed-privatization-reduction.f90 index c61f352b9b055a..b2aa9a3448bd4c 100644 --- a/flang/test/Lower/OpenMP/delayed-privatization-reduction.f90 +++ b/flang/test/Lower/OpenMP/delayed-privatization-reduction.f90 @@ -19,12 +19,12 @@ subroutine red_and_delayed_private end subroutine ! CHECK-LABEL: omp.private {type = private} -! CHECK-SAME: @[[PRIVATIZER_SYM:.*]] : !fir.ref alloc { +! CHECK-SAME: @[[PRIVATIZER_SYM:.*]] : [[TYPE:!fir.shadow, !fir.ref, allocatable : false>]] alloc { ! CHECK-LABEL: omp.reduction.declare ! CHECK-SAME: @[[REDUCTION_SYM:.*]] : i32 init ! CHECK-LABEL: _QPred_and_delayed_private ! CHECK: omp.parallel -! CHECK-SAME: reduction(@[[REDUCTION_SYM]] %{{.*}} -> %arg0 : !fir.ref) -! CHECK-SAME: private(@[[PRIVATIZER_SYM]] %{{.*}} -> %arg1 : !fir.ref) { +! CHECK-SAME: reduction(@[[REDUCTION_SYM]] %{{.*}} -> %{{.*}} : !fir.ref) +! CHECK-SAME: private(@[[PRIVATIZER_SYM]] %{{.*}} -> %{{.*}} : [[TYPE]]) {