aboutsummaryrefslogtreecommitdiff
path: root/flang/lib/Lower
diff options
context:
space:
mode:
Diffstat (limited to 'flang/lib/Lower')
-rw-r--r--flang/lib/Lower/Allocatable.cpp10
-rw-r--r--flang/lib/Lower/Bridge.cpp75
-rw-r--r--flang/lib/Lower/CMakeLists.txt1
-rw-r--r--flang/lib/Lower/CUDA.cpp10
-rw-r--r--flang/lib/Lower/ConvertCall.cpp61
-rw-r--r--flang/lib/Lower/ConvertExpr.cpp2
-rw-r--r--flang/lib/Lower/ConvertExprToHLFIR.cpp13
-rw-r--r--flang/lib/Lower/ConvertVariable.cpp4
-rw-r--r--flang/lib/Lower/HlfirIntrinsics.cpp54
-rw-r--r--flang/lib/Lower/HostAssociations.cpp4
-rw-r--r--flang/lib/Lower/OpenACC.cpp14
-rw-r--r--flang/lib/Lower/OpenMP/Atomic.cpp271
-rw-r--r--flang/lib/Lower/OpenMP/ClauseProcessor.cpp29
-rw-r--r--flang/lib/Lower/OpenMP/ClauseProcessor.h20
-rw-r--r--flang/lib/Lower/OpenMP/Clauses.cpp23
-rw-r--r--flang/lib/Lower/OpenMP/DataSharingProcessor.cpp97
-rw-r--r--flang/lib/Lower/OpenMP/DataSharingProcessor.h35
-rw-r--r--flang/lib/Lower/OpenMP/OpenMP.cpp148
-rw-r--r--flang/lib/Lower/OpenMP/Utils.cpp42
-rw-r--r--flang/lib/Lower/OpenMP/Utils.h24
-rw-r--r--flang/lib/Lower/PFTBuilder.cpp6
-rw-r--r--flang/lib/Lower/Runtime.cpp3
-rw-r--r--flang/lib/Lower/Support/PrivateReductionUtils.cpp2
-rw-r--r--flang/lib/Lower/Support/Utils.cpp22
24 files changed, 434 insertions, 536 deletions
diff --git a/flang/lib/Lower/Allocatable.cpp b/flang/lib/Lower/Allocatable.cpp
index ce9d894..444b5b6 100644
--- a/flang/lib/Lower/Allocatable.cpp
+++ b/flang/lib/Lower/Allocatable.cpp
@@ -490,6 +490,16 @@ private:
return;
}
+ // Preserve characters' dynamic length.
+ if (lenParams.empty() && box.isCharacter() &&
+ !box.hasNonDeferredLenParams()) {
+ auto charTy = mlir::dyn_cast<fir::CharacterType>(box.getEleTy());
+ if (charTy && charTy.hasDynamicLen()) {
+ fir::ExtendedValue exv{box};
+ lenParams.push_back(fir::factory::readCharLen(builder, loc, exv));
+ }
+ }
+
// Generate a sequence of runtime calls.
errorManager.genStatCheck(builder, loc);
genAllocateObjectInit(box, allocatorIdx);
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 7f0907a..c003a5b 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -475,7 +475,9 @@ public:
fir::runtime::genMain(*builder, toLocation(),
bridge.getEnvironmentDefaults(),
getFoldingContext().languageFeatures().IsEnabled(
- Fortran::common::LanguageFeature::CUDA));
+ Fortran::common::LanguageFeature::CUDA),
+ getFoldingContext().languageFeatures().IsEnabled(
+ Fortran::common::LanguageFeature::Coarray));
});
finalizeOpenMPLowering(globalOmpRequiresSymbol);
@@ -1400,21 +1402,23 @@ private:
mlir::Value genLoopVariableAddress(mlir::Location loc,
const Fortran::semantics::Symbol &sym,
bool isUnordered) {
- if (isUnordered || sym.has<Fortran::semantics::HostAssocDetails>() ||
- sym.has<Fortran::semantics::UseDetails>()) {
- if (!shallowLookupSymbol(sym) &&
- !GetSymbolDSA(sym).test(
- Fortran::semantics::Symbol::Flag::OmpShared)) {
- // Do concurrent loop variables are not mapped yet since they are local
- // to the Do concurrent scope (same for OpenMP loops).
- mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint();
- builder->setInsertionPointToStart(builder->getAllocaBlock());
- mlir::Type tempTy = genType(sym);
- mlir::Value temp =
- builder->createTemporaryAlloc(loc, tempTy, toStringRef(sym.name()));
- bindIfNewSymbol(sym, temp);
- builder->restoreInsertionPoint(insPt);
- }
+ if (!shallowLookupSymbol(sym) &&
+ (isUnordered ||
+ GetSymbolDSA(sym).test(Fortran::semantics::Symbol::Flag::OmpPrivate) ||
+ GetSymbolDSA(sym).test(
+ Fortran::semantics::Symbol::Flag::OmpFirstPrivate) ||
+ GetSymbolDSA(sym).test(
+ Fortran::semantics::Symbol::Flag::OmpLastPrivate) ||
+ GetSymbolDSA(sym).test(Fortran::semantics::Symbol::Flag::OmpLinear))) {
+ // Do concurrent loop variables are not mapped yet since they are
+ // local to the Do concurrent scope (same for OpenMP loops).
+ mlir::OpBuilder::InsertPoint insPt = builder->saveInsertionPoint();
+ builder->setInsertionPointToStart(builder->getAllocaBlock());
+ mlir::Type tempTy = genType(sym);
+ mlir::Value temp =
+ builder->createTemporaryAlloc(loc, tempTy, toStringRef(sym.name()));
+ bindIfNewSymbol(sym, temp);
+ builder->restoreInsertionPoint(insPt);
}
auto entry = lookupSymbol(sym);
(void)entry;
@@ -2060,10 +2064,10 @@ private:
// TODO Promote to using `enableDelayedPrivatization` (which is enabled by
// default unlike the staging flag) once the implementation of this is more
// complete.
- bool useDelayedPriv =
- enableDelayedPrivatizationStaging && doConcurrentLoopOp;
+ bool useDelayedPriv = enableDelayedPrivatization && doConcurrentLoopOp;
llvm::SetVector<const Fortran::semantics::Symbol *> allPrivatizedSymbols;
- llvm::SmallSet<const Fortran::semantics::Symbol *, 16> mightHaveReadHostSym;
+ llvm::SmallPtrSet<const Fortran::semantics::Symbol *, 16>
+ mightHaveReadHostSym;
for (const Fortran::semantics::Symbol *symToPrivatize : info.localSymList) {
if (useDelayedPriv) {
@@ -2122,6 +2126,9 @@ private:
}
}
+ if (!doConcurrentLoopOp)
+ return;
+
llvm::SmallVector<bool> reduceVarByRef;
llvm::SmallVector<mlir::Attribute> reductionDeclSymbols;
llvm::SmallVector<mlir::Attribute> nestReduceAttrs;
@@ -4824,7 +4831,9 @@ private:
void genCUDADataTransfer(fir::FirOpBuilder &builder, mlir::Location loc,
const Fortran::evaluate::Assignment &assign,
- hlfir::Entity &lhs, hlfir::Entity &rhs) {
+ hlfir::Entity &lhs, hlfir::Entity &rhs,
+ bool isWholeAllocatableAssignment,
+ bool keepLhsLengthInAllocatableAssignment) {
bool lhsIsDevice = Fortran::evaluate::HasCUDADeviceAttrs(assign.lhs);
bool rhsIsDevice = Fortran::evaluate::HasCUDADeviceAttrs(assign.rhs);
@@ -4889,6 +4898,28 @@ private:
// host = device
if (!lhsIsDevice && rhsIsDevice) {
+ if (Fortran::lower::isTransferWithConversion(rhs)) {
+ mlir::OpBuilder::InsertionGuard insertionGuard(builder);
+ auto elementalOp =
+ mlir::dyn_cast<hlfir::ElementalOp>(rhs.getDefiningOp());
+ assert(elementalOp && "expect elemental op");
+ auto designateOp =
+ *elementalOp.getBody()->getOps<hlfir::DesignateOp>().begin();
+ builder.setInsertionPoint(elementalOp);
+ // Create a temp to transfer the rhs before applying the conversion.
+ hlfir::Entity entity{designateOp.getMemref()};
+ auto [temp, cleanup] = hlfir::createTempFromMold(loc, builder, entity);
+ auto transferKindAttr = cuf::DataTransferKindAttr::get(
+ builder.getContext(), cuf::DataTransferKind::DeviceHost);
+ cuf::DataTransferOp::create(builder, loc, designateOp.getMemref(), temp,
+ /*shape=*/mlir::Value{}, transferKindAttr);
+ designateOp.getMemrefMutable().assign(temp);
+ builder.setInsertionPointAfter(elementalOp);
+ hlfir::AssignOp::create(builder, loc, elementalOp, lhs,
+ isWholeAllocatableAssignment,
+ keepLhsLengthInAllocatableAssignment);
+ return;
+ }
auto transferKindAttr = cuf::DataTransferKindAttr::get(
builder.getContext(), cuf::DataTransferKind::DeviceHost);
cuf::DataTransferOp::create(builder, loc, rhsVal, lhsVal, shape,
@@ -5036,7 +5067,9 @@ private:
hlfir::Entity rhs = evaluateRhs(localStmtCtx);
hlfir::Entity lhs = evaluateLhs(localStmtCtx);
if (isCUDATransfer && !hasCUDAImplicitTransfer)
- genCUDADataTransfer(builder, loc, assign, lhs, rhs);
+ genCUDADataTransfer(builder, loc, assign, lhs, rhs,
+ isWholeAllocatableAssignment,
+ keepLhsLengthInAllocatableAssignment);
else
hlfir::AssignOp::create(builder, loc, rhs, lhs,
isWholeAllocatableAssignment,
diff --git a/flang/lib/Lower/CMakeLists.txt b/flang/lib/Lower/CMakeLists.txt
index 1d1c7ddd..eb4d57d 100644
--- a/flang/lib/Lower/CMakeLists.txt
+++ b/flang/lib/Lower/CMakeLists.txt
@@ -60,6 +60,7 @@ add_flang_library(FortranLower
FortranParser
FortranEvaluate
FortranSemantics
+ FortranUtils
LINK_COMPONENTS
Support
diff --git a/flang/lib/Lower/CUDA.cpp b/flang/lib/Lower/CUDA.cpp
index f6d0078..1293d2c 100644
--- a/flang/lib/Lower/CUDA.cpp
+++ b/flang/lib/Lower/CUDA.cpp
@@ -13,6 +13,7 @@
#include "flang/Lower/CUDA.h"
#include "flang/Lower/AbstractConverter.h"
#include "flang/Optimizer/Builder/Todo.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
#define DEBUG_TYPE "flang-lower-cuda"
@@ -155,3 +156,12 @@ cuf::DataAttributeAttr Fortran::lower::translateSymbolCUFDataAttribute(
Fortran::semantics::GetCUDADataAttr(&sym.GetUltimate());
return cuf::getDataAttribute(mlirContext, cudaAttr);
}
+
+bool Fortran::lower::isTransferWithConversion(mlir::Value rhs) {
+ if (auto elOp = mlir::dyn_cast<hlfir::ElementalOp>(rhs.getDefiningOp()))
+ if (llvm::hasSingleElement(elOp.getBody()->getOps<hlfir::DesignateOp>()) &&
+ llvm::hasSingleElement(elOp.getBody()->getOps<fir::LoadOp>()) == 1 &&
+ llvm::hasSingleElement(elOp.getBody()->getOps<fir::ConvertOp>()) == 1)
+ return true;
+ return false;
+}
diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index bf713f5..04dcc92 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -880,9 +880,10 @@ struct CallContext {
std::optional<mlir::Type> resultType, mlir::Location loc,
Fortran::lower::AbstractConverter &converter,
Fortran::lower::SymMap &symMap,
- Fortran::lower::StatementContext &stmtCtx)
+ Fortran::lower::StatementContext &stmtCtx, bool doCopyIn = true)
: procRef{procRef}, converter{converter}, symMap{symMap},
- stmtCtx{stmtCtx}, resultType{resultType}, loc{loc} {}
+ stmtCtx{stmtCtx}, resultType{resultType}, loc{loc}, doCopyIn{doCopyIn} {
+ }
fir::FirOpBuilder &getBuilder() { return converter.getFirOpBuilder(); }
@@ -924,6 +925,7 @@ struct CallContext {
Fortran::lower::StatementContext &stmtCtx;
std::optional<mlir::Type> resultType;
mlir::Location loc;
+ bool doCopyIn;
};
using ExvAndCleanup =
@@ -1161,18 +1163,6 @@ mlir::Value static getZeroLowerBounds(mlir::Location loc,
return builder.genShift(loc, lowerBounds);
}
-static bool
-isSimplyContiguous(const Fortran::evaluate::ActualArgument &arg,
- Fortran::evaluate::FoldingContext &foldingContext) {
- if (const auto *expr = arg.UnwrapExpr())
- return Fortran::evaluate::IsSimplyContiguous(*expr, foldingContext);
- const Fortran::semantics::Symbol *sym = arg.GetAssumedTypeDummy();
- assert(sym &&
- "expect ActualArguments to be expression or assumed-type symbols");
- return sym->Rank() == 0 ||
- Fortran::evaluate::IsSimplyContiguous(*sym, foldingContext);
-}
-
static bool isParameterObjectOrSubObject(hlfir::Entity entity) {
mlir::Value base = entity;
bool foundParameter = false;
@@ -1204,6 +1194,10 @@ static bool isParameterObjectOrSubObject(hlfir::Entity entity) {
/// fir.box_char...).
/// This function should only be called with an actual that is present.
/// The optional aspects must be handled by this function user.
+///
+/// Note: while Fortran::lower::CallerInterface::PassedEntity (the type of arg)
+/// is technically a template type, in the prepare*ActualArgument() calls
+/// it resolves to Fortran::evaluate::ActualArgument *
static PreparedDummyArgument preparePresentUserCallActualArgument(
mlir::Location loc, fir::FirOpBuilder &builder,
const Fortran::lower::PreparedActualArgument &preparedActual,
@@ -1211,9 +1205,6 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
const Fortran::lower::CallerInterface::PassedEntity &arg,
CallContext &callContext) {
- Fortran::evaluate::FoldingContext &foldingContext =
- callContext.converter.getFoldingContext();
-
// Step 1: get the actual argument, which includes addressing the
// element if this is an array in an elemental call.
hlfir::Entity actual = preparedActual.getActual(loc, builder);
@@ -1254,13 +1245,20 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
passingPolymorphicToNonPolymorphic &&
(actual.isArray() || mlir::isa<fir::BaseBoxType>(dummyType));
- // The simple contiguity of the actual is "lost" when passing a polymorphic
- // to a non polymorphic entity because the dummy dynamic type matters for
- // the contiguity.
- const bool mustDoCopyInOut =
- actual.isArray() && arg.mustBeMadeContiguous() &&
- (passingPolymorphicToNonPolymorphic ||
- !isSimplyContiguous(*arg.entity, foldingContext));
+ bool mustDoCopyIn{false};
+ bool mustDoCopyOut{false};
+
+ if (callContext.doCopyIn) {
+ Fortran::evaluate::FoldingContext &foldingContext{
+ callContext.converter.getFoldingContext()};
+
+ bool suggestCopyIn = Fortran::evaluate::MayNeedCopy(
+ arg.entity, arg.characteristics, foldingContext, /*forCopyOut=*/false);
+ bool suggestCopyOut = Fortran::evaluate::MayNeedCopy(
+ arg.entity, arg.characteristics, foldingContext, /*forCopyOut=*/true);
+ mustDoCopyIn = actual.isArray() && suggestCopyIn;
+ mustDoCopyOut = actual.isArray() && suggestCopyOut;
+ }
const bool actualIsAssumedRank = actual.isAssumedRank();
// Create dummy type with actual argument rank when the dummy is an assumed
@@ -1370,8 +1368,14 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
entity = hlfir::Entity{associate.getBase()};
// Register the temporary destruction after the call.
preparedDummy.pushExprAssociateCleanUp(associate);
- } else if (mustDoCopyInOut) {
+ } else if (mustDoCopyIn || mustDoCopyOut) {
// Copy-in non contiguous variables.
+ //
+ // TODO: copy-in and copy-out are now determined separately, in order
+ // to allow more fine grained copying. While currently both copy-in
+ // and copy-out are must be done together, these copy operations could
+ // be separated in the future. (This is related to TODO comment below.)
+ //
// TODO: for non-finalizable monomorphic derived type actual
// arguments associated with INTENT(OUT) dummy arguments
// we may avoid doing the copy and only allocate the temporary.
@@ -1379,7 +1383,7 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
// allocation for the temp in this case. We can communicate
// this to the codegen via some CopyInOp flag.
// This is a performance concern.
- entity = genCopyIn(entity, arg.mayBeModifiedByCall());
+ entity = genCopyIn(entity, mustDoCopyOut);
}
} else {
const Fortran::lower::SomeExpr *expr = arg.entity->UnwrapExpr();
@@ -2966,8 +2970,11 @@ void Fortran::lower::convertUserDefinedAssignmentToHLFIR(
const evaluate::ProcedureRef &procRef, hlfir::Entity lhs, hlfir::Entity rhs,
Fortran::lower::SymMap &symMap) {
Fortran::lower::StatementContext definedAssignmentContext;
+ // For defined assignment, don't use regular copy-in/copy-out mechanism:
+ // defined assignment generates hlfir.region_assign construct, and this
+ // construct automatically handles any copy-in.
CallContext callContext(procRef, /*resultType=*/std::nullopt, loc, converter,
- symMap, definedAssignmentContext);
+ symMap, definedAssignmentContext, /*doCopyIn=*/false);
Fortran::lower::CallerInterface caller(procRef, converter);
mlir::FunctionType callSiteType = caller.genFunctionType();
PreparedActualArgument preparedLhs{lhs, /*isPresent=*/std::nullopt};
diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp
index 5588f62..d7f94e1 100644
--- a/flang/lib/Lower/ConvertExpr.cpp
+++ b/flang/lib/Lower/ConvertExpr.cpp
@@ -2750,7 +2750,7 @@ public:
fir::unwrapSequenceType(fir::unwrapPassByRefType(argTy))))
TODO(loc, "passing to an OPTIONAL CONTIGUOUS derived type argument "
"with length parameters");
- if (Fortran::evaluate::IsAssumedRank(*expr))
+ if (Fortran::semantics::IsAssumedRank(*expr))
TODO(loc, "passing an assumed rank entity to an OPTIONAL "
"CONTIGUOUS argument");
// Assumed shape VALUE are currently TODO in the call interface
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 9930dd6..81e09a1 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -26,7 +26,6 @@
#include "flang/Optimizer/Builder/Complex.h"
#include "flang/Optimizer/Builder/IntrinsicCall.h"
#include "flang/Optimizer/Builder/MutableBox.h"
-#include "flang/Optimizer/Builder/Runtime/Character.h"
#include "flang/Optimizer/Builder/Runtime/Derived.h"
#include "flang/Optimizer/Builder/Runtime/Pointer.h"
#include "flang/Optimizer/Builder/Todo.h"
@@ -1286,16 +1285,8 @@ struct BinaryOp<Fortran::evaluate::Relational<
fir::FirOpBuilder &builder,
const Op &op, hlfir::Entity lhs,
hlfir::Entity rhs) {
- auto [lhsExv, lhsCleanUp] =
- hlfir::translateToExtendedValue(loc, builder, lhs);
- auto [rhsExv, rhsCleanUp] =
- hlfir::translateToExtendedValue(loc, builder, rhs);
- auto cmp = fir::runtime::genCharCompare(
- builder, loc, translateSignedRelational(op.opr), lhsExv, rhsExv);
- if (lhsCleanUp)
- (*lhsCleanUp)();
- if (rhsCleanUp)
- (*rhsCleanUp)();
+ auto cmp = hlfir::CmpCharOp::create(
+ builder, loc, translateSignedRelational(op.opr), lhs, rhs);
return hlfir::EntityWithAttributes{cmp};
}
};
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index fd66592..80af7f4 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -1720,7 +1720,7 @@ static bool lowerToBoxValue(const Fortran::semantics::Symbol &sym,
return true;
// Assumed rank and optional fir.box cannot yet be read while lowering the
// specifications.
- if (Fortran::evaluate::IsAssumedRank(sym) ||
+ if (Fortran::semantics::IsAssumedRank(sym) ||
Fortran::semantics::IsOptional(sym))
return true;
// Polymorphic entity should be tracked through a fir.box that has the
@@ -2172,7 +2172,7 @@ void Fortran::lower::mapSymbolAttributes(
return;
}
- const bool isAssumedRank = Fortran::evaluate::IsAssumedRank(sym);
+ const bool isAssumedRank = Fortran::semantics::IsAssumedRank(sym);
if (isAssumedRank && !allowAssumedRank)
TODO(loc, "assumed-rank variable in procedure implemented in Fortran");
diff --git a/flang/lib/Lower/HlfirIntrinsics.cpp b/flang/lib/Lower/HlfirIntrinsics.cpp
index 6e1d06a..39595d6 100644
--- a/flang/lib/Lower/HlfirIntrinsics.cpp
+++ b/flang/lib/Lower/HlfirIntrinsics.cpp
@@ -170,6 +170,17 @@ protected:
mlir::Type stmtResultType) override;
};
+class HlfirEOShiftLowering : public HlfirTransformationalIntrinsic {
+public:
+ using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;
+
+protected:
+ mlir::Value
+ lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,
+ const fir::IntrinsicArgumentLoweringRules *argLowering,
+ mlir::Type stmtResultType) override;
+};
+
class HlfirReshapeLowering : public HlfirTransformationalIntrinsic {
public:
using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;
@@ -430,6 +441,46 @@ mlir::Value HlfirCShiftLowering::lowerImpl(
return createOp<hlfir::CShiftOp>(resultType, operands);
}
+mlir::Value HlfirEOShiftLowering::lowerImpl(
+ const Fortran::lower::PreparedActualArguments &loweredActuals,
+ const fir::IntrinsicArgumentLoweringRules *argLowering,
+ mlir::Type stmtResultType) {
+ auto operands = getOperandVector(loweredActuals, argLowering);
+ assert(operands.size() == 4);
+ mlir::Value array = operands[0];
+ mlir::Value shift = operands[1];
+ mlir::Value boundary = operands[2];
+ mlir::Value dim = operands[3];
+ // If DIM is present, then dereference it if it is a ref.
+ if (dim)
+ dim = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{dim});
+
+ mlir::Type resultType = computeResultType(array, stmtResultType);
+
+ if (boundary && fir::isa_trivial(boundary.getType())) {
+ mlir::Type elementType = hlfir::getFortranElementType(resultType);
+ if (auto logicalTy = mlir::dyn_cast<fir::LogicalType>(elementType)) {
+ // Scalar logical constant boundary might be represented using i1, i2, ...
+ // type. We need to cast it to fir.logical type of the ARRAY/result.
+ if (boundary.getType() != logicalTy)
+ boundary = builder.createConvert(loc, logicalTy, boundary);
+ } else {
+ // When the boundary is a constant like '1u', the lowering converts
+ // it into a signless arith.constant value (which is a requirement
+ // of the Arith dialect). If the ARRAY/RESULT is also UNSIGNED,
+ // we have to cast the boundary to the same unsigned type.
+ auto resultIntTy = mlir::dyn_cast<mlir::IntegerType>(elementType);
+ auto boundaryIntTy =
+ mlir::dyn_cast<mlir::IntegerType>(boundary.getType());
+ if (resultIntTy && boundaryIntTy &&
+ resultIntTy.getSignedness() != boundaryIntTy.getSignedness())
+ boundary = builder.createConvert(loc, resultIntTy, boundary);
+ }
+ }
+
+ return createOp<hlfir::EOShiftOp>(resultType, array, shift, boundary, dim);
+}
+
mlir::Value HlfirReshapeLowering::lowerImpl(
const Fortran::lower::PreparedActualArguments &loweredActuals,
const fir::IntrinsicArgumentLoweringRules *argLowering,
@@ -489,6 +540,9 @@ std::optional<hlfir::EntityWithAttributes> Fortran::lower::lowerHlfirIntrinsic(
if (name == "cshift")
return HlfirCShiftLowering{builder, loc}.lower(loweredActuals, argLowering,
stmtResultType);
+ if (name == "eoshift")
+ return HlfirEOShiftLowering{builder, loc}.lower(loweredActuals, argLowering,
+ stmtResultType);
if (name == "reshape")
return HlfirReshapeLowering{builder, loc}.lower(loweredActuals, argLowering,
stmtResultType);
diff --git a/flang/lib/Lower/HostAssociations.cpp b/flang/lib/Lower/HostAssociations.cpp
index 2a330cc..ad6aba1 100644
--- a/flang/lib/Lower/HostAssociations.cpp
+++ b/flang/lib/Lower/HostAssociations.cpp
@@ -431,7 +431,7 @@ public:
mlir::Value box = args.valueInTuple;
mlir::IndexType idxTy = builder.getIndexType();
llvm::SmallVector<mlir::Value> lbounds;
- if (!ba.lboundIsAllOnes() && !Fortran::evaluate::IsAssumedRank(sym)) {
+ if (!ba.lboundIsAllOnes() && !Fortran::semantics::IsAssumedRank(sym)) {
if (ba.isStaticArray()) {
for (std::int64_t lb : ba.staticLBound())
lbounds.emplace_back(builder.createIntegerConstant(loc, idxTy, lb));
@@ -490,7 +490,7 @@ private:
bool isPolymorphic = type && type->IsPolymorphic();
return isScalarOrContiguous && !isPolymorphic &&
!isDerivedWithLenParameters(sym) &&
- !Fortran::evaluate::IsAssumedRank(sym);
+ !Fortran::semantics::IsAssumedRank(sym);
}
};
} // namespace
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 35edcb0..7a84b21 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -1575,7 +1575,7 @@ static void genCombiner(fir::FirOpBuilder &builder, mlir::Location loc,
if (bounds.empty()) {
llvm::SmallVector<mlir::Value> extents;
mlir::Type idxTy = builder.getIndexType();
- for (auto extent : seqTy.getShape()) {
+ for (auto extent : llvm::reverse(seqTy.getShape())) {
mlir::Value lb = mlir::arith::ConstantOp::create(
builder, loc, idxTy, builder.getIntegerAttr(idxTy, 0));
mlir::Value ub = mlir::arith::ConstantOp::create(
@@ -1607,12 +1607,11 @@ static void genCombiner(fir::FirOpBuilder &builder, mlir::Location loc,
}
} else {
// Lowerbound, upperbound and step are passed as block arguments.
- [[maybe_unused]] unsigned nbRangeArgs =
+ unsigned nbRangeArgs =
recipe.getCombinerRegion().getArguments().size() - 2;
assert((nbRangeArgs / 3 == seqTy.getDimension()) &&
"Expect 3 block arguments per dimension");
- for (unsigned i = 2; i < recipe.getCombinerRegion().getArguments().size();
- i += 3) {
+ for (int i = nbRangeArgs - 1; i >= 2; i -= 3) {
mlir::Value lb = recipe.getCombinerRegion().getArgument(i);
mlir::Value ub = recipe.getCombinerRegion().getArgument(i + 1);
mlir::Value step = recipe.getCombinerRegion().getArgument(i + 2);
@@ -1623,8 +1622,11 @@ static void genCombiner(fir::FirOpBuilder &builder, mlir::Location loc,
ivs.push_back(loop.getInductionVar());
}
}
- auto addr1 = fir::CoordinateOp::create(builder, loc, refTy, value1, ivs);
- auto addr2 = fir::CoordinateOp::create(builder, loc, refTy, value2, ivs);
+ llvm::SmallVector<mlir::Value> reversedIvs(ivs.rbegin(), ivs.rend());
+ auto addr1 =
+ fir::CoordinateOp::create(builder, loc, refTy, value1, reversedIvs);
+ auto addr2 =
+ fir::CoordinateOp::create(builder, loc, refTy, value2, reversedIvs);
auto load1 = fir::LoadOp::create(builder, loc, addr1);
auto load2 = fir::LoadOp::create(builder, loc, addr2);
mlir::Value res =
diff --git a/flang/lib/Lower/OpenMP/Atomic.cpp b/flang/lib/Lower/OpenMP/Atomic.cpp
index ed0bff0..ff82a36 100644
--- a/flang/lib/Lower/OpenMP/Atomic.cpp
+++ b/flang/lib/Lower/OpenMP/Atomic.cpp
@@ -43,179 +43,6 @@ namespace omp {
using namespace Fortran::lower::omp;
}
-namespace {
-// An example of a type that can be used to get the return value from
-// the visitor:
-// visitor(type_identity<Xyz>) -> result_type
-using SomeArgType = evaluate::Type<common::TypeCategory::Integer, 4>;
-
-struct GetProc
- : public evaluate::Traverse<GetProc, const evaluate::ProcedureDesignator *,
- false> {
- using Result = const evaluate::ProcedureDesignator *;
- using Base = evaluate::Traverse<GetProc, Result, false>;
- GetProc() : Base(*this) {}
-
- using Base::operator();
-
- static Result Default() { return nullptr; }
-
- Result operator()(const evaluate::ProcedureDesignator &p) const { return &p; }
- static Result Combine(Result a, Result b) { return a != nullptr ? a : b; }
-};
-
-struct WithType {
- WithType(const evaluate::DynamicType &t) : type(t) {
- assert(type.category() != common::TypeCategory::Derived &&
- "Type cannot be a derived type");
- }
-
- template <typename VisitorTy> //
- auto visit(VisitorTy &&visitor) const
- -> std::invoke_result_t<VisitorTy, SomeArgType> {
- switch (type.category()) {
- case common::TypeCategory::Integer:
- switch (type.kind()) {
- case 1:
- return visitor(llvm::type_identity<evaluate::Type<Integer, 1>>{});
- case 2:
- return visitor(llvm::type_identity<evaluate::Type<Integer, 2>>{});
- case 4:
- return visitor(llvm::type_identity<evaluate::Type<Integer, 4>>{});
- case 8:
- return visitor(llvm::type_identity<evaluate::Type<Integer, 8>>{});
- case 16:
- return visitor(llvm::type_identity<evaluate::Type<Integer, 16>>{});
- }
- break;
- case common::TypeCategory::Unsigned:
- switch (type.kind()) {
- case 1:
- return visitor(llvm::type_identity<evaluate::Type<Unsigned, 1>>{});
- case 2:
- return visitor(llvm::type_identity<evaluate::Type<Unsigned, 2>>{});
- case 4:
- return visitor(llvm::type_identity<evaluate::Type<Unsigned, 4>>{});
- case 8:
- return visitor(llvm::type_identity<evaluate::Type<Unsigned, 8>>{});
- case 16:
- return visitor(llvm::type_identity<evaluate::Type<Unsigned, 16>>{});
- }
- break;
- case common::TypeCategory::Real:
- switch (type.kind()) {
- case 2:
- return visitor(llvm::type_identity<evaluate::Type<Real, 2>>{});
- case 3:
- return visitor(llvm::type_identity<evaluate::Type<Real, 3>>{});
- case 4:
- return visitor(llvm::type_identity<evaluate::Type<Real, 4>>{});
- case 8:
- return visitor(llvm::type_identity<evaluate::Type<Real, 8>>{});
- case 10:
- return visitor(llvm::type_identity<evaluate::Type<Real, 10>>{});
- case 16:
- return visitor(llvm::type_identity<evaluate::Type<Real, 16>>{});
- }
- break;
- case common::TypeCategory::Complex:
- switch (type.kind()) {
- case 2:
- return visitor(llvm::type_identity<evaluate::Type<Complex, 2>>{});
- case 3:
- return visitor(llvm::type_identity<evaluate::Type<Complex, 3>>{});
- case 4:
- return visitor(llvm::type_identity<evaluate::Type<Complex, 4>>{});
- case 8:
- return visitor(llvm::type_identity<evaluate::Type<Complex, 8>>{});
- case 10:
- return visitor(llvm::type_identity<evaluate::Type<Complex, 10>>{});
- case 16:
- return visitor(llvm::type_identity<evaluate::Type<Complex, 16>>{});
- }
- break;
- case common::TypeCategory::Logical:
- switch (type.kind()) {
- case 1:
- return visitor(llvm::type_identity<evaluate::Type<Logical, 1>>{});
- case 2:
- return visitor(llvm::type_identity<evaluate::Type<Logical, 2>>{});
- case 4:
- return visitor(llvm::type_identity<evaluate::Type<Logical, 4>>{});
- case 8:
- return visitor(llvm::type_identity<evaluate::Type<Logical, 8>>{});
- }
- break;
- case common::TypeCategory::Character:
- switch (type.kind()) {
- case 1:
- return visitor(llvm::type_identity<evaluate::Type<Character, 1>>{});
- case 2:
- return visitor(llvm::type_identity<evaluate::Type<Character, 2>>{});
- case 4:
- return visitor(llvm::type_identity<evaluate::Type<Character, 4>>{});
- }
- break;
- case common::TypeCategory::Derived:
- (void)Derived;
- break;
- }
- llvm_unreachable("Unhandled type");
- }
-
- const evaluate::DynamicType &type;
-
-private:
- // Shorter names.
- static constexpr auto Character = common::TypeCategory::Character;
- static constexpr auto Complex = common::TypeCategory::Complex;
- static constexpr auto Derived = common::TypeCategory::Derived;
- static constexpr auto Integer = common::TypeCategory::Integer;
- static constexpr auto Logical = common::TypeCategory::Logical;
- static constexpr auto Real = common::TypeCategory::Real;
- static constexpr auto Unsigned = common::TypeCategory::Unsigned;
-};
-
-template <typename T, typename U = std::remove_const_t<T>>
-U AsRvalue(T &t) {
- U copy{t};
- return std::move(copy);
-}
-
-template <typename T>
-T &&AsRvalue(T &&t) {
- return std::move(t);
-}
-
-struct ArgumentReplacer
- : public evaluate::Traverse<ArgumentReplacer, bool, false> {
- using Base = evaluate::Traverse<ArgumentReplacer, bool, false>;
- using Result = bool;
-
- Result Default() const { return false; }
-
- ArgumentReplacer(evaluate::ActualArguments &&newArgs)
- : Base(*this), args_(std::move(newArgs)) {}
-
- using Base::operator();
-
- template <typename T>
- Result operator()(const evaluate::FunctionRef<T> &x) {
- assert(!done_);
- auto &mut = const_cast<evaluate::FunctionRef<T> &>(x);
- mut.arguments() = args_;
- done_ = true;
- return true;
- }
-
- Result Combine(Result &&a, Result &&b) { return a || b; }
-
-private:
- bool done_{false};
- evaluate::ActualArguments &&args_;
-};
-} // namespace
-
[[maybe_unused]] static void
dumpAtomicAnalysis(const parser::OpenMPAtomicConstruct::Analysis &analysis) {
auto whatStr = [](int k) {
@@ -412,85 +239,6 @@ makeMemOrderAttr(lower::AbstractConverter &converter,
return nullptr;
}
-static bool replaceArgs(semantics::SomeExpr &expr,
- evaluate::ActualArguments &&newArgs) {
- return ArgumentReplacer(std::move(newArgs))(expr);
-}
-
-static semantics::SomeExpr makeCall(const evaluate::DynamicType &type,
- const evaluate::ProcedureDesignator &proc,
- const evaluate::ActualArguments &args) {
- return WithType(type).visit([&](auto &&s) -> semantics::SomeExpr {
- using Type = typename llvm::remove_cvref_t<decltype(s)>::type;
- return evaluate::AsGenericExpr(
- evaluate::FunctionRef<Type>(AsRvalue(proc), AsRvalue(args)));
- });
-}
-
-static const evaluate::ProcedureDesignator &
-getProcedureDesignator(const semantics::SomeExpr &call) {
- const evaluate::ProcedureDesignator *proc = GetProc{}(call);
- assert(proc && "Call has no procedure designator");
- return *proc;
-}
-
-static semantics::SomeExpr //
-genReducedMinMax(const semantics::SomeExpr &orig,
- const semantics::SomeExpr *atomArg,
- const std::vector<semantics::SomeExpr> &args) {
- // Take a list of arguments to a min/max operation, e.g. [a0, a1, ...]
- // One of the a_i's, say a_t, must be atomArg.
- // Generate tmp = min/max(a0, a1, ... [except a_t]). Then generate
- // call = min/max(a_t, tmp).
- // Return "call".
-
- // The min/max intrinsics have 2 mandatory arguments, the rest is optional.
- // Make sure that the "tmp = min/max(...)" doesn't promote an optional
- // argument to a non-optional position. This could happen if a_t is at
- // position 0 or 1.
- if (args.size() <= 2)
- return orig;
-
- evaluate::ActualArguments nonAtoms;
-
- auto AsActual = [](const semantics::SomeExpr &x) {
- semantics::SomeExpr copy = x;
- return evaluate::ActualArgument(std::move(copy));
- };
- // Semantic checks guarantee that the "atom" shows exactly once in the
- // argument list (with potential conversions around it).
- // For the first two (non-optional) arguments, if "atom" is among them,
- // replace it with another occurrence of the other non-optional argument.
- if (atomArg == &args[0]) {
- // (atom, x, y...) -> (x, x, y...)
- nonAtoms.push_back(AsActual(args[1]));
- nonAtoms.push_back(AsActual(args[1]));
- } else if (atomArg == &args[1]) {
- // (x, atom, y...) -> (x, x, y...)
- nonAtoms.push_back(AsActual(args[0]));
- nonAtoms.push_back(AsActual(args[0]));
- } else {
- // (x, y, z...) -> unchanged
- nonAtoms.push_back(AsActual(args[0]));
- nonAtoms.push_back(AsActual(args[1]));
- }
-
- // The rest of arguments are optional, so we can just skip "atom".
- for (size_t i = 2, e = args.size(); i != e; ++i) {
- if (atomArg != &args[i])
- nonAtoms.push_back(AsActual(args[i]));
- }
-
- // The type of the intermediate min/max is the same as the type of its
- // arguments, which may be different from the type of the original
- // expression. The original expression may have additional coverts.
- auto tmp =
- makeCall(*atomArg->GetType(), getProcedureDesignator(orig), nonAtoms);
- semantics::SomeExpr call = orig;
- replaceArgs(call, {AsActual(*atomArg), AsActual(tmp)});
- return call;
-}
-
static mlir::Operation * //
genAtomicRead(lower::AbstractConverter &converter,
semantics::SemanticsContext &semaCtx, mlir::Location loc,
@@ -610,25 +358,6 @@ genAtomicUpdate(lower::AbstractConverter &converter,
auto [opcode, args] = evaluate::GetTopLevelOperationIgnoreResizing(input);
assert(!args.empty() && "Update operation without arguments");
- // Pass args as an argument to avoid capturing a structured binding.
- const semantics::SomeExpr *atomArg = [&](auto &args) {
- for (const semantics::SomeExpr &e : args) {
- if (evaluate::IsSameOrConvertOf(e, atom))
- return &e;
- }
- llvm_unreachable("Atomic variable not in argument list");
- }(args);
-
- if (opcode == evaluate::operation::Operator::Min ||
- opcode == evaluate::operation::Operator::Max) {
- // Min and max operations are expanded inline, so reduce them to
- // operations with exactly two (non-optional) arguments.
- rhs = genReducedMinMax(rhs, atomArg, args);
- input = *evaluate::GetConvertInput(rhs);
- std::tie(opcode, args) =
- evaluate::GetTopLevelOperationIgnoreResizing(input);
- atomArg = nullptr; // No longer valid.
- }
for (auto &arg : args) {
if (!evaluate::IsSameOrConvertOf(arg, atom)) {
mlir::Value val = fir::getBase(converter.genExprValue(arg, naCtx, &loc));
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index b98ad3c..6b9bd66 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -19,6 +19,7 @@
#include "flang/Lower/Support/ReductionProcessor.h"
#include "flang/Parser/tools.h"
#include "flang/Semantics/tools.h"
+#include "flang/Utils/OpenMP.h"
#include "llvm/Frontend/OpenMP/OMP.h.inc"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
@@ -647,10 +648,8 @@ addAlignedClause(lower::AbstractConverter &converter,
// The default alignment for some targets is equal to 0.
// Do not generate alignment assumption if alignment is less than or equal to
- // 0.
- if (alignment > 0) {
- // alignment value must be power of 2
- assert((alignment & (alignment - 1)) == 0 && "alignment is not power of 2");
+ // 0 or not a power of two
+ if (alignment > 0 && ((alignment & (alignment - 1)) == 0)) {
auto &objects = std::get<omp::ObjectList>(clause.t);
if (!objects.empty())
genObjectList(objects, converter, alignedVars);
@@ -1179,12 +1178,13 @@ bool ClauseProcessor::processLinear(mlir::omp::LinearClauseOps &result) const {
}
bool ClauseProcessor::processLink(
- llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const {
+ llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const {
return findRepeatableClause<omp::clause::Link>(
[&](const omp::clause::Link &clause, const parser::CharBlock &) {
// Case: declare target link(var1, var2)...
gatherFuncAndVarSyms(
- clause.v, mlir::omp::DeclareTargetCaptureClause::link, result);
+ clause.v, mlir::omp::DeclareTargetCaptureClause::link, result,
+ /*automap=*/false);
});
}
@@ -1280,7 +1280,7 @@ void ClauseProcessor::processMapObjects(
auto location = mlir::NameLoc::get(
mlir::StringAttr::get(firOpBuilder.getContext(), asFortran.str()),
baseOp.getLoc());
- mlir::omp::MapInfoOp mapOp = createMapInfoOp(
+ mlir::omp::MapInfoOp mapOp = utils::openmp::createMapInfoOp(
firOpBuilder, location, baseOp,
/*varPtrPtr=*/mlir::Value{}, asFortran.str(), bounds,
/*members=*/{}, /*membersIndex=*/mlir::ArrayAttr{},
@@ -1507,26 +1507,27 @@ bool ClauseProcessor::processTaskReduction(
}
bool ClauseProcessor::processTo(
- llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const {
+ llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const {
return findRepeatableClause<omp::clause::To>(
[&](const omp::clause::To &clause, const parser::CharBlock &) {
// Case: declare target to(func, var1, var2)...
gatherFuncAndVarSyms(std::get<ObjectList>(clause.t),
- mlir::omp::DeclareTargetCaptureClause::to, result);
+ mlir::omp::DeclareTargetCaptureClause::to, result,
+ /*automap=*/false);
});
}
bool ClauseProcessor::processEnter(
- llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const {
+ llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const {
return findRepeatableClause<omp::clause::Enter>(
[&](const omp::clause::Enter &clause, const parser::CharBlock &source) {
- mlir::Location currentLocation = converter.genLocation(source);
- if (std::get<std::optional<omp::clause::Enter::Modifier>>(clause.t))
- TODO(currentLocation, "Declare target enter AUTOMAP modifier");
+ bool automap =
+ std::get<std::optional<omp::clause::Enter::Modifier>>(clause.t)
+ .has_value();
// Case: declare target enter(func, var1, var2)...
gatherFuncAndVarSyms(std::get<ObjectList>(clause.t),
mlir::omp::DeclareTargetCaptureClause::enter,
- result);
+ result, automap);
});
}
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h
index f8a1f79..c46bdb3 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.h
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h
@@ -118,7 +118,7 @@ public:
bool processDepend(lower::SymMap &symMap, lower::StatementContext &stmtCtx,
mlir::omp::DependClauseOps &result) const;
bool
- processEnter(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
+ processEnter(llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const;
bool processIf(omp::clause::If::DirectiveNameModifier directiveName,
mlir::omp::IfClauseOps &result) const;
bool processInReduction(
@@ -129,7 +129,7 @@ public:
llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSyms) const;
bool processLinear(mlir::omp::LinearClauseOps &result) const;
bool
- processLink(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
+ processLink(llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const;
// This method is used to process a map clause.
// The optional parameter mapSyms is used to store the original Fortran symbol
@@ -150,7 +150,7 @@ public:
bool processTaskReduction(
mlir::Location currentLocation, mlir::omp::TaskReductionClauseOps &result,
llvm::SmallVectorImpl<const semantics::Symbol *> &outReductionSyms) const;
- bool processTo(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
+ bool processTo(llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const;
bool processUseDeviceAddr(
lower::StatementContext &stmtCtx,
mlir::omp::UseDeviceAddrClauseOps &result,
@@ -208,11 +208,15 @@ void ClauseProcessor::processTODO(mlir::Location currentLocation,
if (!x)
return;
unsigned version = semaCtx.langOptions().OpenMPVersion;
- TODO(currentLocation,
- "Unhandled clause " + llvm::omp::getOpenMPClauseName(id).upper() +
- " in " +
- llvm::omp::getOpenMPDirectiveName(directive, version).upper() +
- " construct");
+ bool isSimdDirective = llvm::omp::getOpenMPDirectiveName(directive, version)
+ .upper()
+ .find("SIMD") != llvm::StringRef::npos;
+ if (!semaCtx.langOptions().OpenMPSimd || isSimdDirective)
+ TODO(currentLocation,
+ "Unhandled clause " + llvm::omp::getOpenMPClauseName(id).upper() +
+ " in " +
+ llvm::omp::getOpenMPDirectiveName(directive, version).upper() +
+ " construct");
};
for (ClauseIterator it = clauses.begin(); it != clauses.end(); ++it)
diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index 7f75aae..1a16e1c 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -396,6 +396,8 @@ makePrescriptiveness(parser::OmpPrescriptiveness::Value v) {
switch (v) {
case parser::OmpPrescriptiveness::Value::Strict:
return clause::Prescriptiveness::Strict;
+ case parser::OmpPrescriptiveness::Value::Fallback:
+ return clause::Prescriptiveness::Fallback;
}
llvm_unreachable("Unexpected prescriptiveness");
}
@@ -770,6 +772,27 @@ Doacross make(const parser::OmpClause::Doacross &inp,
// DynamicAllocators: empty
+DynGroupprivate make(const parser::OmpClause::DynGroupprivate &inp,
+ semantics::SemanticsContext &semaCtx) {
+ // imp.v -> OmpDyngroupprivateClause
+ CLAUSET_ENUM_CONVERT( //
+ convert, parser::OmpAccessGroup::Value, DynGroupprivate::AccessGroup,
+ // clang-format off
+ MS(Cgroup, Cgroup)
+ // clang-format on
+ );
+
+ auto &mods = semantics::OmpGetModifiers(inp.v);
+ auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpAccessGroup>(mods);
+ auto *m1 = semantics::OmpGetUniqueModifier<parser::OmpPrescriptiveness>(mods);
+ auto &size = std::get<parser::ScalarIntExpr>(inp.v.t);
+
+ return DynGroupprivate{
+ {/*AccessGroup=*/maybeApplyToV(convert, m0),
+ /*Prescriptiveness=*/maybeApplyToV(makePrescriptiveness, m1),
+ /*Size=*/makeExpr(size, semaCtx)}};
+}
+
Enter make(const parser::OmpClause::Enter &inp,
semantics::SemanticsContext &semaCtx) {
// inp.v -> parser::OmpEnterClause
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
index 67a9a46..146a252 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
@@ -30,18 +30,27 @@
#include "flang/Semantics/tools.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/Frontend/OpenMP/OMP.h"
+#include <variant>
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; }});
+ return eval.visit(common::visitors{
+ [&](const parser::OpenMPConstruct &functionParserNode) {
+ return symDefMap.count(symbol) &&
+ symDefMap.at(symbol) == ConstructPtr(&functionParserNode);
+ },
+ [](const auto &functionParserNode) { return false; }});
+}
+
+bool DataSharingProcessor::OMPConstructSymbolVisitor::
+ isSymbolDefineByNestedDeclaration(const semantics::Symbol *symbol) const {
+ return symDefMap.count(symbol) &&
+ std::holds_alternative<const parser::DeclarationConstruct *>(
+ symDefMap.at(symbol));
}
static bool isConstructWithTopLevelTarget(lower::pft::Evaluation &eval) {
@@ -81,13 +90,14 @@ DataSharingProcessor::DataSharingProcessor(lower::AbstractConverter &converter,
isTargetPrivatization) {}
void DataSharingProcessor::processStep1(
- mlir::omp::PrivateClauseOps *clauseOps) {
+ mlir::omp::PrivateClauseOps *clauseOps,
+ std::optional<llvm::omp::Directive> dir) {
collectSymbolsForPrivatization();
collectDefaultSymbols();
collectImplicitSymbols();
collectPreDeterminedSymbols();
- privatize(clauseOps);
+ privatize(clauseOps, dir);
insertBarrier(clauseOps);
}
@@ -414,47 +424,10 @@ static parser::CharBlock getSource(const semantics::SemanticsContext &semaCtx,
});
}
-static void collectPrivatizingConstructs(
- llvm::SmallSet<llvm::omp::Directive, 16> &constructs, unsigned version) {
- using Clause = llvm::omp::Clause;
- using Directive = llvm::omp::Directive;
-
- static const Clause privatizingClauses[] = {
- Clause::OMPC_private,
- Clause::OMPC_lastprivate,
- Clause::OMPC_firstprivate,
- Clause::OMPC_in_reduction,
- Clause::OMPC_reduction,
- Clause::OMPC_linear,
- // TODO: Clause::OMPC_induction,
- Clause::OMPC_task_reduction,
- Clause::OMPC_detach,
- Clause::OMPC_use_device_ptr,
- Clause::OMPC_is_device_ptr,
- };
-
- for (auto dir : llvm::enum_seq_inclusive<Directive>(Directive::First_,
- Directive::Last_)) {
- bool allowsPrivatizing = llvm::any_of(privatizingClauses, [&](Clause cls) {
- return llvm::omp::isAllowedClauseForDirective(dir, cls, version);
- });
- if (allowsPrivatizing)
- constructs.insert(dir);
- }
-}
-
bool DataSharingProcessor::isOpenMPPrivatizingConstruct(
const parser::OpenMPConstruct &omp, unsigned version) {
- static llvm::SmallSet<llvm::omp::Directive, 16> privatizing;
- [[maybe_unused]] static bool init =
- (collectPrivatizingConstructs(privatizing, version), true);
-
- // As of OpenMP 6.0, privatizing constructs (with the test being if they
- // allow a privatizing clause) are: dispatch, distribute, do, for, loop,
- // parallel, scope, sections, simd, single, target, target_data, task,
- // taskgroup, taskloop, and teams.
- return llvm::is_contained(privatizing,
- parser::omp::GetOmpDirectiveName(omp).v);
+ return llvm::omp::isPrivatizingConstruct(
+ parser::omp::GetOmpDirectiveName(omp).v, version);
}
bool DataSharingProcessor::isOpenMPPrivatizingEvaluation(
@@ -550,11 +523,23 @@ void DataSharingProcessor::collectSymbols(
return false;
}
- return sym->test(semantics::Symbol::Flag::OmpImplicit);
+ // Collect implicit symbols only if they are not defined by a nested
+ // `DeclarationConstruct`. If `sym` is not defined by the current OpenMP
+ // evaluation then it is defined by a block nested within the OpenMP
+ // construct. This, in turn, means that the private allocation for the
+ // symbol will be emitted as part of the nested block and there is no need
+ // to privatize it within the OpenMP construct.
+ return !visitor.isSymbolDefineByNestedDeclaration(sym) &&
+ sym->test(semantics::Symbol::Flag::OmpImplicit);
}
- if (collectPreDetermined)
- return sym->test(semantics::Symbol::Flag::OmpPreDetermined);
+ if (collectPreDetermined) {
+ // Similar to implicit symbols, collect pre-determined symbols only if
+ // they are not defined by a nested `DeclarationConstruct`
+ return visitor.isSymbolDefineBy(sym, eval) &&
+ !visitor.isSymbolDefineByNestedDeclaration(sym) &&
+ sym->test(semantics::Symbol::Flag::OmpPreDetermined);
+ }
return !sym->test(semantics::Symbol::Flag::OmpImplicit) &&
!sym->test(semantics::Symbol::Flag::OmpPreDetermined);
@@ -597,14 +582,15 @@ void DataSharingProcessor::collectPreDeterminedSymbols() {
preDeterminedSymbols);
}
-void DataSharingProcessor::privatize(mlir::omp::PrivateClauseOps *clauseOps) {
+void DataSharingProcessor::privatize(mlir::omp::PrivateClauseOps *clauseOps,
+ std::optional<llvm::omp::Directive> dir) {
for (const semantics::Symbol *sym : allPrivatizedSymbols) {
if (const auto *commonDet =
sym->detailsIf<semantics::CommonBlockDetails>()) {
for (const auto &mem : commonDet->objects())
- privatizeSymbol(&*mem, clauseOps);
+ privatizeSymbol(&*mem, clauseOps, dir);
} else
- privatizeSymbol(sym, clauseOps);
+ privatizeSymbol(sym, clauseOps, dir);
}
}
@@ -623,7 +609,8 @@ void DataSharingProcessor::copyLastPrivatize(mlir::Operation *op) {
void DataSharingProcessor::privatizeSymbol(
const semantics::Symbol *symToPrivatize,
- mlir::omp::PrivateClauseOps *clauseOps) {
+ mlir::omp::PrivateClauseOps *clauseOps,
+ std::optional<llvm::omp::Directive> dir) {
if (!useDelayedPrivatization) {
cloneSymbol(symToPrivatize);
copyFirstPrivateSymbol(symToPrivatize);
@@ -633,7 +620,7 @@ void DataSharingProcessor::privatizeSymbol(
Fortran::lower::privatizeSymbol<mlir::omp::PrivateClauseOp,
mlir::omp::PrivateClauseOps>(
converter, firOpBuilder, symTable, allPrivatizedSymbols,
- mightHaveReadHostSym, symToPrivatize, clauseOps);
+ mightHaveReadHostSym, symToPrivatize, clauseOps, dir);
}
} // namespace omp
} // namespace lower
diff --git a/flang/lib/Lower/OpenMP/DataSharingProcessor.h b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
index 96e7fa6..f6aa865 100644
--- a/flang/lib/Lower/OpenMP/DataSharingProcessor.h
+++ b/flang/lib/Lower/OpenMP/DataSharingProcessor.h
@@ -19,6 +19,7 @@
#include "flang/Parser/parse-tree.h"
#include "flang/Semantics/symbol.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+#include <variant>
namespace mlir {
namespace omp {
@@ -58,20 +59,35 @@ private:
}
void Post(const parser::Name &name) {
- auto *current = !constructs.empty() ? constructs.back() : nullptr;
+ auto current = !constructs.empty() ? constructs.back() : ConstructPtr();
symDefMap.try_emplace(name.symbol, current);
}
- llvm::SmallVector<const parser::OpenMPConstruct *> constructs;
- llvm::DenseMap<semantics::Symbol *, const parser::OpenMPConstruct *>
- symDefMap;
+ bool Pre(const parser::DeclarationConstruct &decl) {
+ constructs.push_back(&decl);
+ return true;
+ }
+
+ void Post(const parser::DeclarationConstruct &decl) {
+ constructs.pop_back();
+ }
/// Given a \p symbol and an \p eval, returns true if eval is the OMP
/// construct that defines symbol.
bool isSymbolDefineBy(const semantics::Symbol *symbol,
lower::pft::Evaluation &eval) const;
+ // Given a \p symbol, returns true if it is defined by a nested
+ // `DeclarationConstruct`.
+ bool
+ isSymbolDefineByNestedDeclaration(const semantics::Symbol *symbol) const;
+
private:
+ using ConstructPtr = std::variant<const parser::OpenMPConstruct *,
+ const parser::DeclarationConstruct *>;
+ llvm::SmallVector<ConstructPtr> constructs;
+ llvm::DenseMap<semantics::Symbol *, ConstructPtr> symDefMap;
+
unsigned version;
};
@@ -91,7 +107,7 @@ private:
lower::pft::Evaluation &eval;
bool shouldCollectPreDeterminedSymbols;
bool useDelayedPrivatization;
- llvm::SmallSet<const semantics::Symbol *, 16> mightHaveReadHostSym;
+ llvm::SmallPtrSet<const semantics::Symbol *, 16> mightHaveReadHostSym;
lower::SymMap &symTable;
bool isTargetPrivatization;
OMPConstructSymbolVisitor visitor;
@@ -110,7 +126,8 @@ private:
void collectDefaultSymbols();
void collectImplicitSymbols();
void collectPreDeterminedSymbols();
- void privatize(mlir::omp::PrivateClauseOps *clauseOps);
+ void privatize(mlir::omp::PrivateClauseOps *clauseOps,
+ std::optional<llvm::omp::Directive> dir = std::nullopt);
void copyLastPrivatize(mlir::Operation *op);
void insertLastPrivateCompare(mlir::Operation *op);
void cloneSymbol(const semantics::Symbol *sym);
@@ -151,7 +168,8 @@ public:
// Step2 performs the copying for lastprivates and requires knowledge of the
// MLIR operation to insert the last private update. Step2 adds
// dealocation code as well.
- void processStep1(mlir::omp::PrivateClauseOps *clauseOps = nullptr);
+ void processStep1(mlir::omp::PrivateClauseOps *clauseOps = nullptr,
+ std::optional<llvm::omp::Directive> dir = std::nullopt);
void processStep2(mlir::Operation *op, bool isLoop);
void pushLoopIV(mlir::Value iv) { loopIVs.push_back(iv); }
@@ -168,7 +186,8 @@ public:
}
void privatizeSymbol(const semantics::Symbol *symToPrivatize,
- mlir::omp::PrivateClauseOps *clauseOps);
+ mlir::omp::PrivateClauseOps *clauseOps,
+ std::optional<llvm::omp::Directive> dir = std::nullopt);
};
} // namespace omp
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 4ce9a0e..574c322 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -38,6 +38,7 @@
#include "flang/Semantics/tools.h"
#include "flang/Support/Flags.h"
#include "flang/Support/OpenMP-utils.h"
+#include "flang/Utils/OpenMP.h"
#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include "mlir/Support/StateStack.h"
@@ -47,6 +48,7 @@
using namespace Fortran::lower::omp;
using namespace Fortran::common::openmp;
+using namespace Fortran::utils::openmp;
//===----------------------------------------------------------------------===//
// Code generation helper functions
@@ -407,7 +409,7 @@ static void processHostEvalClauses(lower::AbstractConverter &converter,
const parser::OmpClauseList *endClauseList = nullptr;
common::visit(
common::visitors{
- [&](const parser::OpenMPBlockConstruct &ompConstruct) {
+ [&](const parser::OmpBlockConstruct &ompConstruct) {
beginClauseList = &ompConstruct.BeginDir().Clauses();
if (auto &endSpec = ompConstruct.EndDir())
endClauseList = &endSpec->Clauses();
@@ -534,6 +536,13 @@ static void processHostEvalClauses(lower::AbstractConverter &converter,
cp.processCollapse(loc, eval, hostInfo->ops, hostInfo->iv);
break;
+ case OMPD_teams_workdistribute:
+ cp.processThreadLimit(stmtCtx, hostInfo->ops);
+ [[fallthrough]];
+ case OMPD_target_teams_workdistribute:
+ cp.processNumTeams(stmtCtx, hostInfo->ops);
+ break;
+
// Standalone 'target' case.
case OMPD_target: {
processSingleNestedIf(
@@ -765,14 +774,14 @@ static void getDeclareTargetInfo(
lower::pft::Evaluation &eval,
const parser::OpenMPDeclareTargetConstruct &declareTargetConstruct,
mlir::omp::DeclareTargetOperands &clauseOps,
- llvm::SmallVectorImpl<DeclareTargetCapturePair> &symbolAndClause) {
+ llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &symbolAndClause) {
const auto &spec =
std::get<parser::OmpDeclareTargetSpecifier>(declareTargetConstruct.t);
if (const auto *objectList{parser::Unwrap<parser::OmpObjectList>(spec.u)}) {
ObjectList objects{makeObjects(*objectList, semaCtx)};
// Case: declare target(func, var1, var2)
gatherFuncAndVarSyms(objects, mlir::omp::DeclareTargetCaptureClause::to,
- symbolAndClause);
+ symbolAndClause, /*automap=*/false);
} else if (const auto *clauseList{
parser::Unwrap<parser::OmpClauseList>(spec.u)}) {
List<Clause> clauses = makeClauses(*clauseList, semaCtx);
@@ -805,21 +814,20 @@ static void collectDeferredDeclareTargets(
llvm::SmallVectorImpl<lower::OMPDeferredDeclareTargetInfo>
&deferredDeclareTarget) {
mlir::omp::DeclareTargetOperands clauseOps;
- llvm::SmallVector<DeclareTargetCapturePair> symbolAndClause;
+ llvm::SmallVector<DeclareTargetCaptureInfo> symbolAndClause;
getDeclareTargetInfo(converter, semaCtx, eval, declareTargetConstruct,
clauseOps, symbolAndClause);
// Return the device type only if at least one of the targets for the
// directive is a function or subroutine
mlir::ModuleOp mod = converter.getFirOpBuilder().getModule();
- for (const DeclareTargetCapturePair &symClause : symbolAndClause) {
- mlir::Operation *op = mod.lookupSymbol(
- converter.mangleName(std::get<const semantics::Symbol &>(symClause)));
+ for (const DeclareTargetCaptureInfo &symClause : symbolAndClause) {
+ mlir::Operation *op =
+ mod.lookupSymbol(converter.mangleName(symClause.symbol));
if (!op) {
- deferredDeclareTarget.push_back({std::get<0>(symClause),
- clauseOps.deviceType,
- std::get<1>(symClause)});
+ deferredDeclareTarget.push_back({symClause.clause, clauseOps.deviceType,
+ symClause.automap, symClause.symbol});
}
}
}
@@ -830,16 +838,16 @@ getDeclareTargetFunctionDevice(
lower::pft::Evaluation &eval,
const parser::OpenMPDeclareTargetConstruct &declareTargetConstruct) {
mlir::omp::DeclareTargetOperands clauseOps;
- llvm::SmallVector<DeclareTargetCapturePair> symbolAndClause;
+ llvm::SmallVector<DeclareTargetCaptureInfo> symbolAndClause;
getDeclareTargetInfo(converter, semaCtx, eval, declareTargetConstruct,
clauseOps, symbolAndClause);
// Return the device type only if at least one of the targets for the
// directive is a function or subroutine
mlir::ModuleOp mod = converter.getFirOpBuilder().getModule();
- for (const DeclareTargetCapturePair &symClause : symbolAndClause) {
- mlir::Operation *op = mod.lookupSymbol(
- converter.mangleName(std::get<const semantics::Symbol &>(symClause)));
+ for (const DeclareTargetCaptureInfo &symClause : symbolAndClause) {
+ mlir::Operation *op =
+ mod.lookupSymbol(converter.mangleName(symClause.symbol));
if (mlir::isa_and_nonnull<mlir::func::FuncOp>(op))
return clauseOps.deviceType;
@@ -1056,7 +1064,7 @@ getImplicitMapTypeAndKind(fir::FirOpBuilder &firOpBuilder,
static void
markDeclareTarget(mlir::Operation *op, lower::AbstractConverter &converter,
mlir::omp::DeclareTargetCaptureClause captureClause,
- mlir::omp::DeclareTargetDeviceType deviceType) {
+ mlir::omp::DeclareTargetDeviceType deviceType, bool automap) {
// TODO: Add support for program local variables with declare target applied
auto declareTargetOp = llvm::dyn_cast<mlir::omp::DeclareTargetInterface>(op);
if (!declareTargetOp)
@@ -1071,11 +1079,11 @@ markDeclareTarget(mlir::Operation *op, lower::AbstractConverter &converter,
if (declareTargetOp.isDeclareTarget()) {
if (declareTargetOp.getDeclareTargetDeviceType() != deviceType)
declareTargetOp.setDeclareTarget(mlir::omp::DeclareTargetDeviceType::any,
- captureClause);
+ captureClause, automap);
return;
}
- declareTargetOp.setDeclareTarget(deviceType, captureClause);
+ declareTargetOp.setDeclareTarget(deviceType, captureClause, automap);
}
//===----------------------------------------------------------------------===//
@@ -2263,7 +2271,8 @@ genOrderedOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
mlir::Location loc, const ConstructQueue &queue,
ConstructQueue::const_iterator item) {
- TODO(loc, "OMPD_ordered");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(loc, "OMPD_ordered");
return nullptr;
}
@@ -2450,7 +2459,8 @@ genScopeOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
mlir::Location loc, const ConstructQueue &queue,
ConstructQueue::const_iterator item) {
- TODO(loc, "Scope construct");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(loc, "Scope construct");
return nullptr;
}
@@ -2819,6 +2829,17 @@ genTeamsOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
queue, item, clauseOps);
}
+static mlir::omp::WorkdistributeOp genWorkdistributeOp(
+ lower::AbstractConverter &converter, lower::SymMap &symTable,
+ semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
+ mlir::Location loc, const ConstructQueue &queue,
+ ConstructQueue::const_iterator item) {
+ return genOpWithBody<mlir::omp::WorkdistributeOp>(
+ OpWithBodyGenInfo(converter, symTable, semaCtx, loc, eval,
+ llvm::omp::Directive::OMPD_workdistribute),
+ queue, item);
+}
+
//===----------------------------------------------------------------------===//
// Code generation functions for the standalone version of constructs that can
// also be a leaf of a composite construct
@@ -3236,7 +3257,7 @@ static mlir::omp::WsloopOp genCompositeDoSimd(
DataSharingProcessor simdItemDSP(converter, semaCtx, simdItem->clauses, eval,
/*shouldCollectPreDeterminedSymbols=*/true,
/*useDelayedPrivatization=*/true, symTable);
- simdItemDSP.processStep1(&simdClauseOps);
+ simdItemDSP.processStep1(&simdClauseOps, simdItem->id);
// Pass the innermost leaf construct's clauses because that's where COLLAPSE
// is placed by construct decomposition.
@@ -3277,7 +3298,8 @@ static mlir::omp::TaskloopOp genCompositeTaskloopSimd(
lower::pft::Evaluation &eval, mlir::Location loc,
const ConstructQueue &queue, ConstructQueue::const_iterator item) {
assert(std::distance(item, queue.end()) == 2 && "Invalid leaf constructs");
- TODO(loc, "Composite TASKLOOP SIMD");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(loc, "Composite TASKLOOP SIMD");
return nullptr;
}
@@ -3449,13 +3471,18 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
break;
case llvm::omp::Directive::OMPD_tile: {
unsigned version = semaCtx.langOptions().OpenMPVersion;
- TODO(loc, "Unhandled loop directive (" +
- llvm::omp::getOpenMPDirectiveName(dir, version) + ")");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(loc, "Unhandled loop directive (" +
+ llvm::omp::getOpenMPDirectiveName(dir, version) + ")");
+ break;
}
case llvm::omp::Directive::OMPD_unroll:
genUnrollOp(converter, symTable, stmtCtx, semaCtx, eval, loc, queue, item);
break;
- // case llvm::omp::Directive::OMPD_workdistribute:
+ case llvm::omp::Directive::OMPD_workdistribute:
+ newOp = genWorkdistributeOp(converter, symTable, semaCtx, eval, loc, queue,
+ item);
+ break;
case llvm::omp::Directive::OMPD_workshare:
newOp = genWorkshareOp(converter, symTable, stmtCtx, semaCtx, eval, loc,
queue, item);
@@ -3485,35 +3512,40 @@ static void
genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
const parser::OpenMPDeclarativeAllocate &declarativeAllocate) {
- TODO(converter.getCurrentLocation(), "OpenMPDeclarativeAllocate");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(converter.getCurrentLocation(), "OpenMPDeclarativeAllocate");
}
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
const parser::OpenMPDeclarativeAssumes &assumesConstruct) {
- TODO(converter.getCurrentLocation(), "OpenMP ASSUMES declaration");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(converter.getCurrentLocation(), "OpenMP ASSUMES declaration");
}
static void
genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
const parser::OmpDeclareVariantDirective &declareVariantDirective) {
- TODO(converter.getCurrentLocation(), "OmpDeclareVariantDirective");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(converter.getCurrentLocation(), "OmpDeclareVariantDirective");
}
static void genOMP(
lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
const parser::OpenMPDeclareReductionConstruct &declareReductionConstruct) {
- TODO(converter.getCurrentLocation(), "OpenMPDeclareReductionConstruct");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(converter.getCurrentLocation(), "OpenMPDeclareReductionConstruct");
}
static void
genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
const parser::OpenMPDeclareSimdConstruct &declareSimdConstruct) {
- TODO(converter.getCurrentLocation(), "OpenMPDeclareSimdConstruct");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(converter.getCurrentLocation(), "OpenMPDeclareSimdConstruct");
}
static void
@@ -3564,14 +3596,14 @@ genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
const parser::OpenMPDeclareTargetConstruct &declareTargetConstruct) {
mlir::omp::DeclareTargetOperands clauseOps;
- llvm::SmallVector<DeclareTargetCapturePair> symbolAndClause;
+ llvm::SmallVector<DeclareTargetCaptureInfo> symbolAndClause;
mlir::ModuleOp mod = converter.getFirOpBuilder().getModule();
getDeclareTargetInfo(converter, semaCtx, eval, declareTargetConstruct,
clauseOps, symbolAndClause);
- for (const DeclareTargetCapturePair &symClause : symbolAndClause) {
- mlir::Operation *op = mod.lookupSymbol(
- converter.mangleName(std::get<const semantics::Symbol &>(symClause)));
+ for (const DeclareTargetCaptureInfo &symClause : symbolAndClause) {
+ mlir::Operation *op =
+ mod.lookupSymbol(converter.mangleName(symClause.symbol));
// Some symbols are deferred until later in the module, these are handled
// upon finalization of the module for OpenMP inside of Bridge, so we simply
@@ -3579,16 +3611,21 @@ genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
if (!op)
continue;
- markDeclareTarget(
- op, converter,
- std::get<mlir::omp::DeclareTargetCaptureClause>(symClause),
- clauseOps.deviceType);
+ markDeclareTarget(op, converter, symClause.clause, clauseOps.deviceType,
+ symClause.automap);
}
}
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
+ const parser::OpenMPGroupprivate &directive) {
+ TODO(converter.getCurrentLocation(), "GROUPPRIVATE");
+}
+
+static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
+ semantics::SemanticsContext &semaCtx,
+ lower::pft::Evaluation &eval,
const parser::OpenMPRequiresConstruct &requiresConstruct) {
// Requires directives are gathered and processed in semantics and
// then combined in the lowering bridge before triggering codegen
@@ -3709,14 +3746,16 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
(void)objects;
(void)clauses;
- TODO(converter.getCurrentLocation(), "OpenMPDepobjConstruct");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(converter.getCurrentLocation(), "OpenMPDepobjConstruct");
}
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
const parser::OpenMPInteropConstruct &interopConstruct) {
- TODO(converter.getCurrentLocation(), "OpenMPInteropConstruct");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(converter.getCurrentLocation(), "OpenMPInteropConstruct");
}
static void
@@ -3732,7 +3771,8 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
const parser::OpenMPAllocatorsConstruct &allocsConstruct) {
- TODO(converter.getCurrentLocation(), "OpenMPAllocatorsConstruct");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(converter.getCurrentLocation(), "OpenMPAllocatorsConstruct");
}
//===----------------------------------------------------------------------===//
@@ -3749,7 +3789,7 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
- const parser::OpenMPBlockConstruct &blockConstruct) {
+ const parser::OmpBlockConstruct &blockConstruct) {
const parser::OmpDirectiveSpecification &beginSpec =
blockConstruct.BeginDir();
List<Clause> clauses = makeClauses(beginSpec.Clauses(), semaCtx);
@@ -3798,7 +3838,8 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
!std::holds_alternative<clause::Detach>(clause.u)) {
std::string name =
parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(clause.id));
- TODO(clauseLocation, name + " clause is not implemented yet");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(clauseLocation, name + " clause is not implemented yet");
}
}
@@ -3814,7 +3855,8 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
lower::pft::Evaluation &eval,
const parser::OpenMPAssumeConstruct &assumeConstruct) {
mlir::Location clauseLocation = converter.genLocation(assumeConstruct.source);
- TODO(clauseLocation, "OpenMP ASSUME construct");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(clauseLocation, "OpenMP ASSUME construct");
}
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
@@ -3850,21 +3892,24 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
const parser::OpenMPUtilityConstruct &) {
- TODO(converter.getCurrentLocation(), "OpenMPUtilityConstruct");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(converter.getCurrentLocation(), "OpenMPUtilityConstruct");
}
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
const parser::OpenMPDispatchConstruct &) {
- TODO(converter.getCurrentLocation(), "OpenMPDispatchConstruct");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(converter.getCurrentLocation(), "OpenMPDispatchConstruct");
}
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
const parser::OpenMPExecutableAllocate &execAllocConstruct) {
- TODO(converter.getCurrentLocation(), "OpenMPExecutableAllocate");
+ if (!semaCtx.langOptions().OpenMPSimd)
+ TODO(converter.getCurrentLocation(), "OpenMPExecutableAllocate");
}
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
@@ -3936,9 +3981,12 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
List<Clause> clauses = makeClauses(
std::get<parser::OmpClauseList>(beginSectionsDirective.t), semaCtx);
const auto &endSectionsDirective =
- std::get<parser::OmpEndSectionsDirective>(sectionsConstruct.t);
+ std::get<std::optional<parser::OmpEndSectionsDirective>>(
+ sectionsConstruct.t);
+ assert(endSectionsDirective &&
+ "Missing end section directive should have been handled in semantics");
clauses.append(makeClauses(
- std::get<parser::OmpClauseList>(endSectionsDirective.t), semaCtx));
+ std::get<parser::OmpClauseList>(endSectionsDirective->t), semaCtx));
mlir::Location currentLocation = converter.getCurrentLocation();
llvm::omp::Directive directive =
@@ -4102,7 +4150,7 @@ void Fortran::lower::genDeclareTargetIntGlobal(
bool Fortran::lower::isOpenMPTargetConstruct(
const parser::OpenMPConstruct &omp) {
llvm::omp::Directive dir = llvm::omp::Directive::OMPD_unknown;
- if (const auto *block = std::get_if<parser::OpenMPBlockConstruct>(&omp.u)) {
+ if (const auto *block = std::get_if<parser::OmpBlockConstruct>(&omp.u)) {
dir = block->BeginDir().DirId();
} else if (const auto *loop =
std::get_if<parser::OpenMPLoopConstruct>(&omp.u)) {
@@ -4176,7 +4224,7 @@ bool Fortran::lower::markOpenMPDeferredDeclareTargetFunctions(
deviceCodeFound = true;
markDeclareTarget(op, converter, declTar.declareTargetCaptureClause,
- devType);
+ devType, declTar.automap);
}
return deviceCodeFound;
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index 13fda97..cb6dd57 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -24,6 +24,7 @@
#include <flang/Parser/parse-tree.h>
#include <flang/Parser/tools.h>
#include <flang/Semantics/tools.h>
+#include <flang/Utils/OpenMP.h>
#include <llvm/Support/CommandLine.h>
#include <iterator>
@@ -102,41 +103,10 @@ getIterationVariableSymbol(const lower::pft::Evaluation &eval) {
void gatherFuncAndVarSyms(
const ObjectList &objects, mlir::omp::DeclareTargetCaptureClause clause,
- llvm::SmallVectorImpl<DeclareTargetCapturePair> &symbolAndClause) {
+ llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &symbolAndClause,
+ bool automap) {
for (const Object &object : objects)
- symbolAndClause.emplace_back(clause, *object.sym());
-}
-
-mlir::omp::MapInfoOp
-createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value baseAddr, mlir::Value varPtrPtr,
- llvm::StringRef name, llvm::ArrayRef<mlir::Value> bounds,
- llvm::ArrayRef<mlir::Value> members,
- mlir::ArrayAttr membersIndex, uint64_t mapType,
- mlir::omp::VariableCaptureKind mapCaptureType, mlir::Type retTy,
- bool partialMap, mlir::FlatSymbolRefAttr mapperId) {
- if (auto boxTy = llvm::dyn_cast<fir::BaseBoxType>(baseAddr.getType())) {
- baseAddr = fir::BoxAddrOp::create(builder, loc, baseAddr);
- retTy = baseAddr.getType();
- }
-
- mlir::TypeAttr varType = mlir::TypeAttr::get(
- llvm::cast<mlir::omp::PointerLikeType>(retTy).getElementType());
-
- // For types with unknown extents such as <2x?xi32> we discard the incomplete
- // type info and only retain the base type. The correct dimensions are later
- // recovered through the bounds info.
- if (auto seqType = llvm::dyn_cast<fir::SequenceType>(varType.getValue()))
- if (seqType.hasDynamicExtents())
- varType = mlir::TypeAttr::get(seqType.getEleTy());
-
- mlir::omp::MapInfoOp op = mlir::omp::MapInfoOp::create(
- builder, loc, retTy, baseAddr, varType,
- builder.getIntegerAttr(builder.getIntegerType(64, false), mapType),
- builder.getAttr<mlir::omp::VariableCaptureKindAttr>(mapCaptureType),
- varPtrPtr, members, membersIndex, bounds, mapperId,
- builder.getStringAttr(name), builder.getBoolAttr(partialMap));
- return op;
+ symbolAndClause.emplace_back(clause, *object.sym(), automap);
}
// This function gathers the individual omp::Object's that make up a
@@ -402,7 +372,7 @@ mlir::Value createParentSymAndGenIntermediateMaps(
// Create a map for the intermediate member and insert it and it's
// indices into the parentMemberIndices list to track it.
- mlir::omp::MapInfoOp mapOp = createMapInfoOp(
+ mlir::omp::MapInfoOp mapOp = utils::openmp::createMapInfoOp(
firOpBuilder, clauseLocation, curValue,
/*varPtrPtr=*/mlir::Value{}, asFortran,
/*bounds=*/interimBounds,
@@ -562,7 +532,7 @@ void insertChildMapInfoIntoParent(
converter.getCurrentLocation(), asFortran, bounds,
treatIndexAsSection);
- mlir::omp::MapInfoOp mapOp = createMapInfoOp(
+ mlir::omp::MapInfoOp mapOp = utils::openmp::createMapInfoOp(
firOpBuilder, info.rawInput.getLoc(), info.rawInput,
/*varPtrPtr=*/mlir::Value(), asFortran.str(), bounds, members,
firOpBuilder.create2DI64ArrayAttr(
diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h
index 11641ba..88371ab 100644
--- a/flang/lib/Lower/OpenMP/Utils.h
+++ b/flang/lib/Lower/OpenMP/Utils.h
@@ -42,8 +42,15 @@ class AbstractConverter;
namespace omp {
-using DeclareTargetCapturePair =
- std::pair<mlir::omp::DeclareTargetCaptureClause, const semantics::Symbol &>;
+struct DeclareTargetCaptureInfo {
+ mlir::omp::DeclareTargetCaptureClause clause;
+ bool automap = false;
+ const semantics::Symbol &symbol;
+
+ DeclareTargetCaptureInfo(mlir::omp::DeclareTargetCaptureClause c,
+ const semantics::Symbol &s, bool a = false)
+ : clause(c), automap(a), symbol(s) {}
+};
// A small helper structure for keeping track of a component members MapInfoOp
// and index data when lowering OpenMP map clauses. Keeps track of the
@@ -107,16 +114,6 @@ struct OmpMapParentAndMemberData {
semantics::SemanticsContext &semaCtx);
};
-mlir::omp::MapInfoOp
-createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value baseAddr, mlir::Value varPtrPtr,
- llvm::StringRef name, llvm::ArrayRef<mlir::Value> bounds,
- llvm::ArrayRef<mlir::Value> members,
- mlir::ArrayAttr membersIndex, uint64_t mapType,
- mlir::omp::VariableCaptureKind mapCaptureType, mlir::Type retTy,
- bool partialMap = false,
- mlir::FlatSymbolRefAttr mapperId = mlir::FlatSymbolRefAttr());
-
void insertChildMapInfoIntoParent(
Fortran::lower::AbstractConverter &converter,
Fortran::semantics::SemanticsContext &semaCtx,
@@ -150,7 +147,8 @@ getIterationVariableSymbol(const lower::pft::Evaluation &eval);
void gatherFuncAndVarSyms(
const ObjectList &objects, mlir::omp::DeclareTargetCaptureClause clause,
- llvm::SmallVectorImpl<DeclareTargetCapturePair> &symbolAndClause);
+ llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &symbolAndClause,
+ bool automap = false);
int64_t getCollapseValue(const List<Clause> &clauses);
diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index a28cc01..80f31c2 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -1742,11 +1742,11 @@ private:
layeredVarList[i].end());
}
- llvm::SmallSet<const semantics::Symbol *, 32> seen;
+ llvm::SmallPtrSet<const semantics::Symbol *, 32> seen;
std::vector<Fortran::lower::pft::VariableList> layeredVarList;
- llvm::SmallSet<const semantics::Symbol *, 32> aliasSyms;
+ llvm::SmallPtrSet<const semantics::Symbol *, 32> aliasSyms;
/// Set of scopes that have been analyzed for aliases.
- llvm::SmallSet<const semantics::Scope *, 4> analyzedScopes;
+ llvm::SmallPtrSet<const semantics::Scope *, 4> analyzedScopes;
std::vector<Fortran::lower::pft::Variable::AggregateStore> stores;
};
} // namespace
diff --git a/flang/lib/Lower/Runtime.cpp b/flang/lib/Lower/Runtime.cpp
index fc59a24..494dd49 100644
--- a/flang/lib/Lower/Runtime.cpp
+++ b/flang/lib/Lower/Runtime.cpp
@@ -39,8 +39,7 @@ static void genUnreachable(fir::FirOpBuilder &builder, mlir::Location loc) {
if (parentOp->getDialect()->getNamespace() ==
mlir::omp::OpenMPDialect::getDialectNamespace())
Fortran::lower::genOpenMPTerminator(builder, parentOp, loc);
- else if (parentOp->getDialect()->getNamespace() ==
- mlir::acc::OpenACCDialect::getDialectNamespace())
+ else if (Fortran::lower::isInsideOpenACCComputeConstruct(builder))
Fortran::lower::genOpenACCTerminator(builder, parentOp, loc);
else
fir::UnreachableOp::create(builder, loc);
diff --git a/flang/lib/Lower/Support/PrivateReductionUtils.cpp b/flang/lib/Lower/Support/PrivateReductionUtils.cpp
index fff060b..1b09801 100644
--- a/flang/lib/Lower/Support/PrivateReductionUtils.cpp
+++ b/flang/lib/Lower/Support/PrivateReductionUtils.cpp
@@ -616,6 +616,8 @@ void PopulateInitAndCleanupRegionsHelper::populateByRefInitAndCleanupRegions() {
assert(sym && "Symbol information is required to privatize derived types");
assert(!scalarInitValue && "ScalarInitvalue is unused for privatization");
}
+ if (hlfir::Entity{moldArg}.isAssumedRank())
+ TODO(loc, "Privatization of assumed rank variable");
mlir::Type valTy = fir::unwrapRefType(argType);
if (fir::isa_trivial(valTy)) {
diff --git a/flang/lib/Lower/Support/Utils.cpp b/flang/lib/Lower/Support/Utils.cpp
index 881401e..1b4d37e 100644
--- a/flang/lib/Lower/Support/Utils.cpp
+++ b/flang/lib/Lower/Support/Utils.cpp
@@ -654,8 +654,9 @@ void privatizeSymbol(
lower::AbstractConverter &converter, fir::FirOpBuilder &firOpBuilder,
lower::SymMap &symTable,
llvm::SetVector<const semantics::Symbol *> &allPrivatizedSymbols,
- llvm::SmallSet<const semantics::Symbol *, 16> &mightHaveReadHostSym,
- const semantics::Symbol *symToPrivatize, OperandsStructType *clauseOps) {
+ llvm::SmallPtrSet<const semantics::Symbol *, 16> &mightHaveReadHostSym,
+ const semantics::Symbol *symToPrivatize, OperandsStructType *clauseOps,
+ std::optional<llvm::omp::Directive> dir) {
constexpr bool isDoConcurrent =
std::is_same_v<OpType, fir::LocalitySpecifierOp>;
mlir::OpBuilder::InsertPoint dcIP;
@@ -676,6 +677,13 @@ void privatizeSymbol(
bool emitCopyRegion =
symToPrivatize->test(semantics::Symbol::Flag::OmpFirstPrivate) ||
symToPrivatize->test(semantics::Symbol::Flag::LocalityLocalInit);
+ // A symbol attached to the simd directive can have the firstprivate flag set
+ // on it when it is also used in a non-firstprivate privatization clause.
+ // For instance: $omp do simd lastprivate(a) firstprivate(a)
+ // We cannot apply the firstprivate privatizer to simd, so make sure we do
+ // not emit the copy region when dealing with the SIMD directive.
+ if (dir && dir == llvm::omp::Directive::OMPD_simd)
+ emitCopyRegion = false;
mlir::Value privVal = hsb.getAddr();
mlir::Type allocType = privVal.getType();
@@ -846,17 +854,19 @@ privatizeSymbol<mlir::omp::PrivateClauseOp, mlir::omp::PrivateClauseOps>(
lower::AbstractConverter &converter, fir::FirOpBuilder &firOpBuilder,
lower::SymMap &symTable,
llvm::SetVector<const semantics::Symbol *> &allPrivatizedSymbols,
- llvm::SmallSet<const semantics::Symbol *, 16> &mightHaveReadHostSym,
+ llvm::SmallPtrSet<const semantics::Symbol *, 16> &mightHaveReadHostSym,
const semantics::Symbol *symToPrivatize,
- mlir::omp::PrivateClauseOps *clauseOps);
+ mlir::omp::PrivateClauseOps *clauseOps,
+ std::optional<llvm::omp::Directive> dir);
template void
privatizeSymbol<fir::LocalitySpecifierOp, fir::LocalitySpecifierOperands>(
lower::AbstractConverter &converter, fir::FirOpBuilder &firOpBuilder,
lower::SymMap &symTable,
llvm::SetVector<const semantics::Symbol *> &allPrivatizedSymbols,
- llvm::SmallSet<const semantics::Symbol *, 16> &mightHaveReadHostSym,
+ llvm::SmallPtrSet<const semantics::Symbol *, 16> &mightHaveReadHostSym,
const semantics::Symbol *symToPrivatize,
- fir::LocalitySpecifierOperands *clauseOps);
+ fir::LocalitySpecifierOperands *clauseOps,
+ std::optional<llvm::omp::Directive> dir);
} // end namespace Fortran::lower