@@ -2150,6 +2150,70 @@ privatizeIv(Fortran::lower::AbstractConverter &converter,
2150
2150
ivPrivate.push_back (privateValue);
2151
2151
}
2152
2152
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
+
2153
2217
static mlir::acc::LoopOp createLoopOp (
2154
2218
Fortran::lower::AbstractConverter &converter,
2155
2219
mlir::Location currentLocation,
@@ -2482,6 +2546,9 @@ static mlir::acc::LoopOp createLoopOp(
2482
2546
loopOp.setTileOperandsSegmentsAttr (
2483
2547
builder.getDenseI32ArrayAttr (tileOperandsSegments));
2484
2548
2549
+ // Determine the loop's default par mode - either seq, independent, or auto.
2550
+ determineDefaultLoopParMode (converter, loopOp, seqDeviceTypes,
2551
+ independentDeviceTypes, autoDeviceTypes);
2485
2552
if (!seqDeviceTypes.empty ())
2486
2553
loopOp.setSeqAttr (builder.getArrayAttr (seqDeviceTypes));
2487
2554
if (!independentDeviceTypes.empty ())
0 commit comments