@@ -2150,6 +2150,70 @@ privatizeIv(Fortran::lower::AbstractConverter &converter,
21502150 ivPrivate.push_back (privateValue);
21512151}
21522152
2153+ static void determineDefaultLoopParMode (
2154+ Fortran::lower::AbstractConverter &converter, mlir::acc::LoopOp &loopOp,
2155+ llvm::SmallVector<mlir::Attribute> &seqDeviceTypes,
2156+ llvm::SmallVector<mlir::Attribute> &independentDeviceTypes,
2157+ llvm::SmallVector<mlir::Attribute> &autoDeviceTypes) {
2158+ auto hasDeviceNone = [](mlir::Attribute attr) -> bool {
2159+ return mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr).getValue () ==
2160+ mlir::acc::DeviceType::None;
2161+ };
2162+ bool hasDefaultSeq = llvm::any_of (seqDeviceTypes, hasDeviceNone);
2163+ bool hasDefaultIndependent =
2164+ llvm::any_of (independentDeviceTypes, hasDeviceNone);
2165+ bool hasDefaultAuto = llvm::any_of (autoDeviceTypes, hasDeviceNone);
2166+ if (hasDefaultSeq || hasDefaultIndependent || hasDefaultAuto)
2167+ return ; // Default loop par mode is already specified.
2168+
2169+ mlir::Region *currentRegion =
2170+ converter.getFirOpBuilder ().getBlock ()->getParent ();
2171+ mlir::Operation *parentOp = mlir::acc::getEnclosingComputeOp (*currentRegion);
2172+ const bool isOrphanedLoop = !parentOp;
2173+ if (isOrphanedLoop ||
2174+ mlir::isa_and_present<mlir::acc::ParallelOp>(parentOp)) {
2175+ // As per OpenACC 3.3 standard section 2.9.6 independent clause:
2176+ // A loop construct with no auto or seq clause is treated as if it has the
2177+ // independent clause when it is an orphaned loop construct or its parent
2178+ // compute construct is a parallel construct.
2179+ independentDeviceTypes.push_back (mlir::acc::DeviceTypeAttr::get (
2180+ converter.getFirOpBuilder ().getContext (), mlir::acc::DeviceType::None));
2181+ } else if (mlir::isa_and_present<mlir::acc::SerialOp>(parentOp)) {
2182+ // Serial construct implies `seq` clause on loop. However, this
2183+ // conflicts with parallelism assignment if already set. Therefore check
2184+ // that first.
2185+ bool hasDefaultGangWorkerOrVector =
2186+ loopOp.hasVector () || loopOp.getVectorValue () || loopOp.hasWorker () ||
2187+ loopOp.getWorkerValue () || loopOp.hasGang () ||
2188+ loopOp.getGangValue (mlir::acc::GangArgType::Num) ||
2189+ loopOp.getGangValue (mlir::acc::GangArgType::Dim) ||
2190+ loopOp.getGangValue (mlir::acc::GangArgType::Static);
2191+ if (!hasDefaultGangWorkerOrVector)
2192+ seqDeviceTypes.push_back (mlir::acc::DeviceTypeAttr::get (
2193+ converter.getFirOpBuilder ().getContext (),
2194+ mlir::acc::DeviceType::None));
2195+ // Since the loop has some parallelism assigned - we cannot assign `seq`.
2196+ // However, the `acc.loop` verifier will check that one of seq, independent,
2197+ // or auto is marked. Seems reasonable to mark as auto since the OpenACC
2198+ // spec does say "If not, or if it is unable to make a determination, it
2199+ // must treat the auto clause as if it is a seq clause, and it must
2200+ // ignore any gang, worker, or vector clauses on the loop construct"
2201+ else
2202+ autoDeviceTypes.push_back (mlir::acc::DeviceTypeAttr::get (
2203+ converter.getFirOpBuilder ().getContext (),
2204+ mlir::acc::DeviceType::None));
2205+ } else {
2206+ // As per OpenACC 3.3 standard section 2.9.7 auto clause:
2207+ // When the parent compute construct is a kernels construct, a loop
2208+ // construct with no independent or seq clause is treated as if it has the
2209+ // auto clause.
2210+ assert (mlir::isa_and_present<mlir::acc::KernelsOp>(parentOp) &&
2211+ " Expected kernels construct" );
2212+ autoDeviceTypes.push_back (mlir::acc::DeviceTypeAttr::get (
2213+ converter.getFirOpBuilder ().getContext (), mlir::acc::DeviceType::None));
2214+ }
2215+ }
2216+
21532217static mlir::acc::LoopOp createLoopOp (
21542218 Fortran::lower::AbstractConverter &converter,
21552219 mlir::Location currentLocation,
@@ -2482,6 +2546,9 @@ static mlir::acc::LoopOp createLoopOp(
24822546 loopOp.setTileOperandsSegmentsAttr (
24832547 builder.getDenseI32ArrayAttr (tileOperandsSegments));
24842548
2549+ // Determine the loop's default par mode - either seq, independent, or auto.
2550+ determineDefaultLoopParMode (converter, loopOp, seqDeviceTypes,
2551+ independentDeviceTypes, autoDeviceTypes);
24852552 if (!seqDeviceTypes.empty ())
24862553 loopOp.setSeqAttr (builder.getArrayAttr (seqDeviceTypes));
24872554 if (!independentDeviceTypes.empty ())
0 commit comments