diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.td b/flang/include/flang/Optimizer/Dialect/FIRAttr.td index 3ebc24951cfff..2845080030b92 100644 --- a/flang/include/flang/Optimizer/Dialect/FIRAttr.td +++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.td @@ -200,4 +200,23 @@ def fir_OpenMPSafeTempArrayCopyAttr : fir_Attr<"OpenMPSafeTempArrayCopy"> { }]; } +def LocalitySpecTypeLocal : I32EnumAttrCase<"Local", 0, "local">; +def LocalitySpecTypeLocalInit + : I32EnumAttrCase<"LocalInit", 1, "local_init">; + +def LocalitySpecifierType : I32EnumAttr< + "LocalitySpecifierType", + "Type of a locality specifier", [ + LocalitySpecTypeLocal, + LocalitySpecTypeLocalInit + ]> { + let genSpecializedAttr = 0; + let cppNamespace = "::fir"; +} + +def LocalitySpecifierTypeAttr : EnumAttr { + let assemblyFormat = "`{` `type` `=` $value `}`"; +} + #endif // FIR_DIALECT_FIR_ATTRS diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index 0ba985641069b..acc0c6967c739 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -3485,6 +3485,137 @@ def fir_BoxTotalElementsOp let hasCanonicalizer = 1; } +def YieldOp : fir_Op<"yield", + [Pure, ReturnLike, Terminator, + ParentOneOf<["LocalitySpecifierOp"]>]> { + let summary = "loop yield and termination operation"; + let description = [{ + "fir.yield" yields SSA values from a fir dialect op region and + terminates the region. The semantics of how the values are yielded is + defined by the parent operation. + }]; + + let arguments = (ins Variadic:$results); + + let builders = [ + OpBuilder<(ins), [{ build($_builder, $_state, {}); }]> + ]; + + let assemblyFormat = "( `(` $results^ `:` type($results) `)` )? attr-dict"; +} + +def fir_LocalitySpecifierOp : fir_Op<"local", [IsolatedFromAbove]> { + let summary = "Provides declaration of local and local_init logic."; + let description = [{ + This operation provides a declaration of how to implement the + localization of a variable. The dialect users should provide + which type should be allocated for this variable. The allocated (usually by + alloca) variable is passed to the initialization region which does everything + else (e.g. initialization of Fortran runtime descriptors). Information about + how to initialize the copy from the original item should be given in the + copy region, and if needed, how to deallocate memory (allocated by the + initialization region) in the dealloc region. + + Examples: + + * `local(x)` would not need any regions because no initialization is + required by the standard for i32 variables and this is not local_init. + ``` + fir.local {type = local} @x.localizer : i32 + ``` + + * `local_init(x)` would be emitted as: + ``` + fir.local {type = local_init} @x.localizer : i32 copy { + ^bb0(%arg0: !fir.ref, %arg1: !fir.ref): + // %arg0 is the original host variable. + // %arg1 represents the memory allocated for this private variable. + ... copy from host to the localized clone .... + fir.yield(%arg1 : !fir.ref) + } + ``` + + * `local(x)` for "allocatables" would be emitted as: + ``` + fir.local {type = local} @x.localizer : !some.type init { + ^bb0(%arg0: !fir.ref, %arg1: !fir.ref): + // initialize %arg1, using %arg0 as a mold for allocations. + // For example if %arg0 is a heap allocated array with a runtime determined + // length and !some.type is a runtime type descriptor, the init region + // will read the array length from %arg0, and heap allocate an array of the + // right length and initialize %arg1 to contain the array allocation and + // length. + fir.yield(%arg1 : !fir.ref) + } dealloc { + ^bb0(%arg0: !fir.ref): + // ... deallocate memory allocated by the init region... + // In the example above, this will free the heap allocated array data. + fir.yield + } + ``` + + There are no restrictions on the body except for: + - The `dealloc` regions has a single argument. + - The `init` & `copy` regions have 2 arguments. + - All three regions are terminated by `fir.yield` ops. + The above restrictions and other obvious restrictions (e.g. verifying the + type of yielded values) are verified by the custom op verifier. The actual + contents of the blocks inside all regions are not verified. + + Instances of this op would then be used by ops that model directives that + accept data-sharing attribute clauses. + + The `sym_name` attribute provides a symbol by which the privatizer op can be + referenced by other dialect ops. + + The `type` attribute is the type of the value being localized. This type + will be implicitly allocated in MLIR->LLVMIR conversion and passed as the + second argument to the init region. Therefore the type of arguments to + the regions should be a type which represents a pointer to `type`. + + The `locality_specifier_type` attribute specifies whether the localized + corresponds to a `local` or a `local_init` specifier. + }]; + + let arguments = (ins SymbolNameAttr:$sym_name, + TypeAttrOf:$type, + LocalitySpecifierTypeAttr:$locality_specifier_type); + + let regions = (region AnyRegion:$init_region, + AnyRegion:$copy_region, + AnyRegion:$dealloc_region); + + let assemblyFormat = [{ + $locality_specifier_type $sym_name `:` $type + (`init` $init_region^)? + (`copy` $copy_region^)? + (`dealloc` $dealloc_region^)? + attr-dict + }]; + + let builders = [ + OpBuilder<(ins CArg<"mlir::TypeRange">:$result, + CArg<"mlir::StringAttr">:$sym_name, + CArg<"mlir::TypeAttr">:$type)> + ]; + + let extraClassDeclaration = [{ + /// Get the type for arguments to nested regions. This should + /// generally be either the same as getType() or some pointer + /// type (pointing to the type allocated by this op). + /// This method will return Type{nullptr} if there are no nested + /// regions. + mlir::Type getArgType() { + for (mlir::Region *region : getRegions()) + for (mlir::Type ty : region->getArgumentTypes()) + return ty; + return nullptr; + } + }]; + + let hasRegionVerifier = 1; +} + def fir_DoConcurrentOp : fir_Op<"do_concurrent", [SingleBlock, AutomaticAllocationScope]> { let summary = "do concurrent loop wrapper"; diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 72c63e4e314d2..8da05255d5f41 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -94,10 +94,11 @@ struct IncrementLoopInfo { template explicit IncrementLoopInfo(Fortran::semantics::Symbol &sym, const T &lower, const T &upper, const std::optional &step, - bool isUnordered = false) + bool isConcurrent = false) : loopVariableSym{&sym}, lowerExpr{Fortran::semantics::GetExpr(lower)}, upperExpr{Fortran::semantics::GetExpr(upper)}, - stepExpr{Fortran::semantics::GetExpr(step)}, isUnordered{isUnordered} {} + stepExpr{Fortran::semantics::GetExpr(step)}, + isConcurrent{isConcurrent} {} IncrementLoopInfo(IncrementLoopInfo &&) = default; IncrementLoopInfo &operator=(IncrementLoopInfo &&x) = default; @@ -120,7 +121,7 @@ struct IncrementLoopInfo { const Fortran::lower::SomeExpr *upperExpr; const Fortran::lower::SomeExpr *stepExpr; const Fortran::lower::SomeExpr *maskExpr = nullptr; - bool isUnordered; // do concurrent, forall + bool isConcurrent; llvm::SmallVector localSymList; llvm::SmallVector localInitSymList; llvm::SmallVector< @@ -130,7 +131,7 @@ struct IncrementLoopInfo { mlir::Value loopVariable = nullptr; // Data members for structured loops. - fir::DoLoopOp doLoop = nullptr; + mlir::Operation *loopOp = nullptr; // Data members for unstructured loops. bool hasRealControl = false; @@ -1981,7 +1982,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { llvm_unreachable("illegal reduction operator"); } - /// Collect DO CONCURRENT or FORALL loop control information. + /// Collect DO CONCURRENT loop control information. IncrementLoopNestInfo getConcurrentControl( const Fortran::parser::ConcurrentHeader &header, const std::list &localityList = {}) { @@ -2292,8 +2293,14 @@ class FirConverter : public Fortran::lower::AbstractConverter { mlir::LLVM::LoopAnnotationAttr la = mlir::LLVM::LoopAnnotationAttr::get( builder->getContext(), {}, /*vectorize=*/va, {}, /*unroll*/ ua, /*unroll_and_jam*/ uja, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}); - if (has_attrs) - info.doLoop.setLoopAnnotationAttr(la); + if (has_attrs) { + if (auto loopOp = mlir::dyn_cast(info.loopOp)) + loopOp.setLoopAnnotationAttr(la); + + if (auto doConcurrentOp = + mlir::dyn_cast(info.loopOp)) + doConcurrentOp.setLoopAnnotationAttr(la); + } } /// Generate FIR to begin a structured or unstructured increment loop nest. @@ -2302,96 +2309,77 @@ class FirConverter : public Fortran::lower::AbstractConverter { llvm::SmallVectorImpl &dirs) { assert(!incrementLoopNestInfo.empty() && "empty loop nest"); mlir::Location loc = toLocation(); - mlir::Operation *boundsAndStepIP = nullptr; mlir::arith::IntegerOverflowFlags iofBackup{}; + llvm::SmallVector nestLBs; + llvm::SmallVector nestUBs; + llvm::SmallVector nestSts; + llvm::SmallVector nestReduceOperands; + llvm::SmallVector nestReduceAttrs; + bool genDoConcurrent = false; + for (IncrementLoopInfo &info : incrementLoopNestInfo) { - mlir::Value lowerValue; - mlir::Value upperValue; - mlir::Value stepValue; + genDoConcurrent = info.isStructured() && info.isConcurrent; - { - mlir::OpBuilder::InsertionGuard guard(*builder); + if (!genDoConcurrent) + info.loopVariable = genLoopVariableAddress(loc, *info.loopVariableSym, + info.isConcurrent); - // Set the IP before the first loop in the nest so that all nest bounds - // and step values are created outside the nest. - if (boundsAndStepIP) - builder->setInsertionPointAfter(boundsAndStepIP); + if (!getLoweringOptions().getIntegerWrapAround()) { + iofBackup = builder->getIntegerOverflowFlags(); + builder->setIntegerOverflowFlags( + mlir::arith::IntegerOverflowFlags::nsw); + } - info.loopVariable = genLoopVariableAddress(loc, *info.loopVariableSym, - info.isUnordered); - if (!getLoweringOptions().getIntegerWrapAround()) { - iofBackup = builder->getIntegerOverflowFlags(); - builder->setIntegerOverflowFlags( - mlir::arith::IntegerOverflowFlags::nsw); - } - lowerValue = genControlValue(info.lowerExpr, info); - upperValue = genControlValue(info.upperExpr, info); - bool isConst = true; - stepValue = genControlValue(info.stepExpr, info, - info.isStructured() ? nullptr : &isConst); - if (!getLoweringOptions().getIntegerWrapAround()) - builder->setIntegerOverflowFlags(iofBackup); - boundsAndStepIP = stepValue.getDefiningOp(); - - // Use a temp variable for unstructured loops with non-const step. - if (!isConst) { - info.stepVariable = - builder->createTemporary(loc, stepValue.getType()); - boundsAndStepIP = - builder->create(loc, stepValue, info.stepVariable); + nestLBs.push_back(genControlValue(info.lowerExpr, info)); + nestUBs.push_back(genControlValue(info.upperExpr, info)); + bool isConst = true; + nestSts.push_back(genControlValue( + info.stepExpr, info, info.isStructured() ? nullptr : &isConst)); + + if (!getLoweringOptions().getIntegerWrapAround()) + builder->setIntegerOverflowFlags(iofBackup); + + // Use a temp variable for unstructured loops with non-const step. + if (!isConst) { + mlir::Value stepValue = nestSts.back(); + info.stepVariable = builder->createTemporary(loc, stepValue.getType()); + builder->create(loc, stepValue, info.stepVariable); + } + + if (genDoConcurrent && nestReduceOperands.empty()) { + // Create DO CONCURRENT reduce operands and attributes + for (const auto &reduceSym : info.reduceSymList) { + const fir::ReduceOperationEnum reduceOperation = reduceSym.first; + const Fortran::semantics::Symbol *sym = reduceSym.second; + fir::ExtendedValue exv = getSymbolExtendedValue(*sym, nullptr); + nestReduceOperands.push_back(fir::getBase(exv)); + auto reduceAttr = + fir::ReduceAttr::get(builder->getContext(), reduceOperation); + nestReduceAttrs.push_back(reduceAttr); } } + } + for (auto [info, lowerValue, upperValue, stepValue] : + llvm::zip_equal(incrementLoopNestInfo, nestLBs, nestUBs, nestSts)) { // Structured loop - generate fir.do_loop. if (info.isStructured()) { + if (genDoConcurrent) + continue; + + // The loop variable is a doLoop op argument. mlir::Type loopVarType = info.getLoopVariableType(); - mlir::Value loopValue; - if (info.isUnordered) { - llvm::SmallVector reduceOperands; - llvm::SmallVector reduceAttrs; - // Create DO CONCURRENT reduce operands and attributes - for (const auto &reduceSym : info.reduceSymList) { - const fir::ReduceOperationEnum reduce_operation = reduceSym.first; - const Fortran::semantics::Symbol *sym = reduceSym.second; - fir::ExtendedValue exv = getSymbolExtendedValue(*sym, nullptr); - reduceOperands.push_back(fir::getBase(exv)); - auto reduce_attr = - fir::ReduceAttr::get(builder->getContext(), reduce_operation); - reduceAttrs.push_back(reduce_attr); - } - // The loop variable value is explicitly updated. - info.doLoop = builder->create( - loc, lowerValue, upperValue, stepValue, /*unordered=*/true, - /*finalCountValue=*/false, /*iterArgs=*/std::nullopt, - llvm::ArrayRef(reduceOperands), reduceAttrs); - builder->setInsertionPointToStart(info.doLoop.getBody()); - loopValue = builder->createConvert(loc, loopVarType, - info.doLoop.getInductionVar()); - } else { - // The loop variable is a doLoop op argument. - info.doLoop = builder->create( - loc, lowerValue, upperValue, stepValue, /*unordered=*/false, - /*finalCountValue=*/true, - builder->createConvert(loc, loopVarType, lowerValue)); - builder->setInsertionPointToStart(info.doLoop.getBody()); - loopValue = info.doLoop.getRegionIterArgs()[0]; - } + auto loopOp = builder->create( + loc, lowerValue, upperValue, stepValue, /*unordered=*/false, + /*finalCountValue=*/true, + builder->createConvert(loc, loopVarType, lowerValue)); + info.loopOp = loopOp; + builder->setInsertionPointToStart(loopOp.getBody()); + mlir::Value loopValue = loopOp.getRegionIterArgs()[0]; + // Update the loop variable value in case it has non-index references. builder->create(loc, loopValue, info.loopVariable); - if (info.maskExpr) { - Fortran::lower::StatementContext stmtCtx; - mlir::Value maskCond = createFIRExpr(loc, info.maskExpr, stmtCtx); - stmtCtx.finalizeAndReset(); - mlir::Value maskCondCast = - builder->createConvert(loc, builder->getI1Type(), maskCond); - auto ifOp = builder->create(loc, maskCondCast, - /*withElseRegion=*/false); - builder->setInsertionPointToStart(&ifOp.getThenRegion().front()); - } - if (info.hasLocalitySpecs()) - handleLocalitySpecs(info); - addLoopAnnotationAttr(info, dirs); continue; } @@ -2455,6 +2443,60 @@ class FirConverter : public Fortran::lower::AbstractConverter { builder->restoreInsertionPoint(insertPt); } } + + if (genDoConcurrent) { + auto loopWrapperOp = builder->create(loc); + builder->setInsertionPointToStart( + builder->createBlock(&loopWrapperOp.getRegion())); + + for (IncrementLoopInfo &info : llvm::reverse(incrementLoopNestInfo)) { + info.loopVariable = genLoopVariableAddress(loc, *info.loopVariableSym, + info.isConcurrent); + } + + builder->setInsertionPointToEnd(loopWrapperOp.getBody()); + auto loopOp = builder->create( + loc, nestLBs, nestUBs, nestSts, nestReduceOperands, + nestReduceAttrs.empty() + ? nullptr + : mlir::ArrayAttr::get(builder->getContext(), nestReduceAttrs), + nullptr); + + llvm::SmallVector loopBlockArgTypes( + incrementLoopNestInfo.size(), builder->getIndexType()); + llvm::SmallVector loopBlockArgLocs( + incrementLoopNestInfo.size(), loc); + mlir::Region &loopRegion = loopOp.getRegion(); + mlir::Block *loopBlock = builder->createBlock( + &loopRegion, loopRegion.begin(), loopBlockArgTypes, loopBlockArgLocs); + builder->setInsertionPointToStart(loopBlock); + + for (auto [info, blockArg] : + llvm::zip_equal(incrementLoopNestInfo, loopBlock->getArguments())) { + info.loopOp = loopOp; + mlir::Value loopValue = + builder->createConvert(loc, info.getLoopVariableType(), blockArg); + builder->create(loc, loopValue, info.loopVariable); + + if (info.maskExpr) { + Fortran::lower::StatementContext stmtCtx; + mlir::Value maskCond = createFIRExpr(loc, info.maskExpr, stmtCtx); + stmtCtx.finalizeAndReset(); + mlir::Value maskCondCast = + builder->createConvert(loc, builder->getI1Type(), maskCond); + auto ifOp = builder->create(loc, maskCondCast, + /*withElseRegion=*/false); + builder->setInsertionPointToStart(&ifOp.getThenRegion().front()); + } + } + + IncrementLoopInfo &innermostInfo = incrementLoopNestInfo.back(); + + if (innermostInfo.hasLocalitySpecs()) + handleLocalitySpecs(innermostInfo); + + addLoopAnnotationAttr(innermostInfo, dirs); + } } /// Generate FIR to end a structured or unstructured increment loop nest. @@ -2471,29 +2513,31 @@ class FirConverter : public Fortran::lower::AbstractConverter { it != rend; ++it) { IncrementLoopInfo &info = *it; if (info.isStructured()) { - // End fir.do_loop. - if (info.isUnordered) { - builder->setInsertionPointAfter(info.doLoop); + // End fir.do_concurent.loop. + if (info.isConcurrent) { + builder->setInsertionPointAfter(info.loopOp->getParentOp()); continue; } + + // End fir.do_loop. // Decrement tripVariable. - builder->setInsertionPointToEnd(info.doLoop.getBody()); + auto doLoopOp = mlir::cast(info.loopOp); + builder->setInsertionPointToEnd(doLoopOp.getBody()); llvm::SmallVector results; results.push_back(builder->create( - loc, info.doLoop.getInductionVar(), info.doLoop.getStep(), - iofAttr)); + loc, doLoopOp.getInductionVar(), doLoopOp.getStep(), iofAttr)); // Step loopVariable to help optimizations such as vectorization. // Induction variable elimination will clean up as necessary. mlir::Value step = builder->createConvert( - loc, info.getLoopVariableType(), info.doLoop.getStep()); + loc, info.getLoopVariableType(), doLoopOp.getStep()); mlir::Value loopVar = builder->create(loc, info.loopVariable); results.push_back( builder->create(loc, loopVar, step, iofAttr)); builder->create(loc, results); - builder->setInsertionPointAfter(info.doLoop); + builder->setInsertionPointAfter(doLoopOp); // The loop control variable may be used after the loop. - builder->create(loc, info.doLoop.getResult(1), + builder->create(loc, doLoopOp.getResult(1), info.loopVariable); continue; } diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp index 1d6e1502ed0f9..86166db355f72 100644 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -280,6 +280,9 @@ mlir::Block *fir::FirOpBuilder::getAllocaBlock() { if (auto cufKernelOp = getRegion().getParentOfType()) return &cufKernelOp.getRegion().front(); + if (auto doConcurentOp = getRegion().getParentOfType()) + return doConcurentOp.getBody(); + return getEntryBlock(); } diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index 05ef69169bae5..955acbe7018d3 100644 --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -4909,6 +4909,105 @@ void fir::BoxTotalElementsOp::getCanonicalizationPatterns( patterns.add(context); } +//===----------------------------------------------------------------------===// +// LocalitySpecifierOp +//===----------------------------------------------------------------------===// + +llvm::LogicalResult fir::LocalitySpecifierOp::verifyRegions() { + mlir::Type argType = getArgType(); + auto verifyTerminator = [&](mlir::Operation *terminator, + bool yieldsValue) -> llvm::LogicalResult { + if (!terminator->getBlock()->getSuccessors().empty()) + return llvm::success(); + + if (!llvm::isa(terminator)) + return mlir::emitError(terminator->getLoc()) + << "expected exit block terminator to be an `fir.yield` op."; + + YieldOp yieldOp = llvm::cast(terminator); + mlir::TypeRange yieldedTypes = yieldOp.getResults().getTypes(); + + if (!yieldsValue) { + if (yieldedTypes.empty()) + return llvm::success(); + + return mlir::emitError(terminator->getLoc()) + << "Did not expect any values to be yielded."; + } + + if (yieldedTypes.size() == 1 && yieldedTypes.front() == argType) + return llvm::success(); + + auto error = mlir::emitError(yieldOp.getLoc()) + << "Invalid yielded value. Expected type: " << argType + << ", got: "; + + if (yieldedTypes.empty()) + error << "None"; + else + error << yieldedTypes; + + return error; + }; + + auto verifyRegion = [&](mlir::Region ®ion, unsigned expectedNumArgs, + llvm::StringRef regionName, + bool yieldsValue) -> llvm::LogicalResult { + assert(!region.empty()); + + if (region.getNumArguments() != expectedNumArgs) + return mlir::emitError(region.getLoc()) + << "`" << regionName << "`: " + << "expected " << expectedNumArgs + << " region arguments, got: " << region.getNumArguments(); + + for (mlir::Block &block : region) { + // MLIR will verify the absence of the terminator for us. + if (!block.mightHaveTerminator()) + continue; + + if (failed(verifyTerminator(block.getTerminator(), yieldsValue))) + return llvm::failure(); + } + + return llvm::success(); + }; + + // Ensure all of the region arguments have the same type + for (mlir::Region *region : getRegions()) + for (mlir::Type ty : region->getArgumentTypes()) + if (ty != argType) + return emitError() << "Region argument type mismatch: got " << ty + << " expected " << argType << "."; + + mlir::Region &initRegion = getInitRegion(); + if (!initRegion.empty() && + failed(verifyRegion(getInitRegion(), /*expectedNumArgs=*/2, "init", + /*yieldsValue=*/true))) + return llvm::failure(); + + LocalitySpecifierType dsType = getLocalitySpecifierType(); + + if (dsType == LocalitySpecifierType::Local && !getCopyRegion().empty()) + return emitError("`local` specifiers do not require a `copy` region."); + + if (dsType == LocalitySpecifierType::LocalInit && getCopyRegion().empty()) + return emitError( + "`local_init` specifiers require at least a `copy` region."); + + if (dsType == LocalitySpecifierType::LocalInit && + failed(verifyRegion(getCopyRegion(), /*expectedNumArgs=*/2, "copy", + /*yieldsValue=*/true))) + return llvm::failure(); + + if (!getDeallocRegion().empty() && + failed(verifyRegion(getDeallocRegion(), /*expectedNumArgs=*/1, "dealloc", + /*yieldsValue=*/false))) + return llvm::failure(); + + return llvm::success(); +} + //===----------------------------------------------------------------------===// // DoConcurrentOp //===----------------------------------------------------------------------===// diff --git a/flang/test/Fir/do_concurrent.fir b/flang/test/Fir/do_concurrent.fir index 8e80ffb9c7b0b..4e55777402428 100644 --- a/flang/test/Fir/do_concurrent.fir +++ b/flang/test/Fir/do_concurrent.fir @@ -90,3 +90,22 @@ func.func @dc_2d_reduction(%i_lb: index, %i_ub: index, %i_st: index, // CHECK: fir.store %[[J_IV_CVT]] to %[[J]] : !fir.ref // CHECK: } // CHECK: } + + +fir.local {type = local} @local_privatizer : i32 + +// CHECK: fir.local {type = local} @[[LOCAL_PRIV_SYM:local_privatizer]] : i32 + +fir.local {type = local_init} @local_init_privatizer : i32 copy { +^bb0(%arg0: !fir.ref, %arg1: !fir.ref): + %0 = fir.load %arg0 : !fir.ref + fir.store %0 to %arg1 : !fir.ref + fir.yield(%arg1 : !fir.ref) +} + +// CHECK: fir.local {type = local_init} @[[LOCAL_INIT_PRIV_SYM:local_init_privatizer]] : i32 +// CHECK: ^bb0(%[[ORIG_VAL:.*]]: !fir.ref, %[[LOCAL_VAL:.*]]: !fir.ref): +// CHECK: %[[ORIG_VAL_LD:.*]] = fir.load %[[ORIG_VAL]] +// CHECK: fir.store %[[ORIG_VAL_LD]] to %[[LOCAL_VAL]] : !fir.ref +// CHECK: fir.yield(%[[LOCAL_VAL]] : !fir.ref) +// CHECK: } diff --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir index f9f5e267dd9bc..733227339bc39 100644 --- a/flang/test/Fir/invalid.fir +++ b/flang/test/Fir/invalid.fir @@ -1,5 +1,3 @@ - - // RUN: fir-opt -split-input-file -verify-diagnostics --strict-fir-volatile-verifier %s // expected-error@+1{{custom op 'fir.string_lit' must have character type}} @@ -1311,3 +1309,79 @@ func.func @bad_convert_volatile6(%arg0: !fir.ref) -> !fir.ref { %0 = fir.volatile_cast %arg0 : (!fir.ref) -> !fir.ref return %0 : !fir.ref } + +// ----- + +fir.local {type = local} @x.localizer : i32 init { +^bb0(%arg0: i32, %arg1: i32): + %0 = arith.constant 0.0 : f32 + // expected-error @below {{Invalid yielded value. Expected type: 'i32', got: 'f32'}} + fir.yield(%0 : f32) +} + +// ----- + +// expected-error @below {{Region argument type mismatch: got 'f32' expected 'i32'.}} +fir.local {type = local} @x.localizer : i32 init { +^bb0(%arg0: i32, %arg1: f32): + fir.yield +} + +// ----- + +fir.local {type = local} @x.localizer : f32 init { +^bb0(%arg0: f32, %arg1: f32): + fir.yield(%arg0: f32) +} dealloc { +^bb0(%arg0: f32): + // expected-error @below {{Did not expect any values to be yielded.}} + fir.yield(%arg0 : f32) +} + +// ----- + +fir.local {type = local} @x.localizer : i32 init { +^bb0(%arg0: i32, %arg1: i32): + // expected-error @below {{expected exit block terminator to be an `fir.yield` op.}} + fir.unreachable +} + +// ----- + +// expected-error @below {{`init`: expected 2 region arguments, got: 1}} +fir.local {type = local} @x.localizer : f32 init { +^bb0(%arg0: f32): + fir.yield(%arg0 : f32) +} + +// ----- + +// expected-error @below {{`copy`: expected 2 region arguments, got: 1}} +fir.local {type = local_init} @x.privatizer : f32 copy { +^bb0(%arg0: f32): + fir.yield(%arg0 : f32) +} + +// ----- + +// expected-error @below {{`dealloc`: expected 1 region arguments, got: 2}} +fir.local {type = local} @x.localizer : f32 dealloc { +^bb0(%arg0: f32, %arg1: f32): + fir.yield +} + +// ----- + +// expected-error @below {{`local` specifiers do not require a `copy` region.}} +fir.local {type = local} @x.localizer : f32 copy { +^bb0(%arg0: f32, %arg1 : f32): + fir.yield(%arg0 : f32) +} + +// ----- + +// expected-error @below {{`local_init` specifiers require at least a `copy` region.}} +fir.local {type = local_init} @x.localizer : f32 init { +^bb0(%arg0: f32, %arg1: f32): + fir.yield(%arg0 : f32) +} diff --git a/flang/test/Lower/do_concurrent.f90 b/flang/test/Lower/do_concurrent.f90 index ef93d2d6b035b..cc113f59c35e3 100644 --- a/flang/test/Lower/do_concurrent.f90 +++ b/flang/test/Lower/do_concurrent.f90 @@ -14,6 +14,9 @@ subroutine sub1(n) implicit none integer :: n, m, i, j, k integer, dimension(n) :: a +!CHECK: %[[N_DECL:.*]]:2 = hlfir.declare %{{.*}} dummy_scope %{{.*}} {uniq_name = "_QFsub1En"} +!CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub1Ea"} + !CHECK: %[[LB1:.*]] = arith.constant 1 : i32 !CHECK: %[[LB1_CVT:.*]] = fir.convert %[[LB1]] : (i32) -> index !CHECK: %[[UB1:.*]] = fir.load %{{.*}}#0 : !fir.ref @@ -29,10 +32,30 @@ subroutine sub1(n) !CHECK: %[[UB3:.*]] = arith.constant 10 : i32 !CHECK: %[[UB3_CVT:.*]] = fir.convert %[[UB3]] : (i32) -> index -!CHECK: fir.do_loop %{{.*}} = %[[LB1_CVT]] to %[[UB1_CVT]] step %{{.*}} unordered -!CHECK: fir.do_loop %{{.*}} = %[[LB2_CVT]] to %[[UB2_CVT]] step %{{.*}} unordered -!CHECK: fir.do_loop %{{.*}} = %[[LB3_CVT]] to %[[UB3_CVT]] step %{{.*}} unordered +!CHECK: fir.do_concurrent +!CHECK: %[[I:.*]] = fir.alloca i32 {bindc_name = "i"} +!CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %[[I]] +!CHECK: %[[J:.*]] = fir.alloca i32 {bindc_name = "j"} +!CHECK: %[[J_DECL:.*]]:2 = hlfir.declare %[[J]] +!CHECK: %[[K:.*]] = fir.alloca i32 {bindc_name = "k"} +!CHECK: %[[K_DECL:.*]]:2 = hlfir.declare %[[K]] + +!CHECK: fir.do_concurrent.loop (%[[I_IV:.*]], %[[J_IV:.*]], %[[K_IV:.*]]) = +!CHECK-SAME: (%[[LB1_CVT]], %[[LB2_CVT]], %[[LB3_CVT]]) to +!CHECK-SAME: (%[[UB1_CVT]], %[[UB2_CVT]], %[[UB3_CVT]]) step +!CHECK-SAME: (%{{.*}}, %{{.*}}, %{{.*}}) { +!CHECK: %[[I_IV_CVT:.*]] = fir.convert %[[I_IV]] : (index) -> i32 +!CHECK: fir.store %[[I_IV_CVT]] to %[[I_DECL]]#0 : !fir.ref +!CHECK: %[[J_IV_CVT:.*]] = fir.convert %[[J_IV]] : (index) -> i32 +!CHECK: fir.store %[[J_IV_CVT]] to %[[J_DECL]]#0 : !fir.ref +!CHECK: %[[K_IV_CVT:.*]] = fir.convert %[[K_IV]] : (index) -> i32 +!CHECK: fir.store %[[K_IV_CVT]] to %[[K_DECL]]#0 : !fir.ref +!CHECK: %[[N_VAL:.*]] = fir.load %[[N_DECL]]#0 : !fir.ref +!CHECK: %[[I_VAL:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref +!CHECK: %[[I_VAL_CVT:.*]] = fir.convert %[[I_VAL]] : (i32) -> i64 +!CHECK: %[[A_ELEM:.*]] = hlfir.designate %[[A_DECL]]#0 (%[[I_VAL_CVT]]) +!CHECK: hlfir.assign %[[N_VAL]] to %[[A_ELEM]] : i32, !fir.ref do concurrent(i=1:n, j=1:bar(n*m, n/m), k=5:10) a(i) = n end do @@ -45,14 +68,17 @@ subroutine sub2(n) integer, dimension(n) :: a !CHECK: %[[LB1:.*]] = arith.constant 1 : i32 !CHECK: %[[LB1_CVT:.*]] = fir.convert %[[LB1]] : (i32) -> index -!CHECK: %[[UB1:.*]] = fir.load %5#0 : !fir.ref +!CHECK: %[[UB1:.*]] = fir.load %{{.*}}#0 : !fir.ref !CHECK: %[[UB1_CVT:.*]] = fir.convert %[[UB1]] : (i32) -> index -!CHECK: fir.do_loop %{{.*}} = %[[LB1_CVT]] to %[[UB1_CVT]] step %{{.*}} unordered +!CHECK: fir.do_concurrent +!CHECK: fir.do_concurrent.loop (%{{.*}}) = (%[[LB1_CVT]]) to (%[[UB1_CVT]]) step (%{{.*}}) + !CHECK: %[[LB2:.*]] = arith.constant 1 : i32 !CHECK: %[[LB2_CVT:.*]] = fir.convert %[[LB2]] : (i32) -> index !CHECK: %[[UB2:.*]] = fir.call @_QPbar(%{{.*}}, %{{.*}}) proc_attrs fastmath : (!fir.ref, !fir.ref) -> i32 !CHECK: %[[UB2_CVT:.*]] = fir.convert %[[UB2]] : (i32) -> index -!CHECK: fir.do_loop %{{.*}} = %[[LB2_CVT]] to %[[UB2_CVT]] step %{{.*}} unordered +!CHECK: fir.do_concurrent +!CHECK: fir.do_concurrent.loop (%{{.*}}) = (%[[LB2_CVT]]) to (%[[UB2_CVT]]) step (%{{.*}}) do concurrent(i=1:n) do concurrent(j=1:bar(n*m, n/m)) a(i) = n @@ -60,7 +86,6 @@ subroutine sub2(n) end do end subroutine - !CHECK-LABEL: unstructured subroutine unstructured(inner_step) integer(4) :: i, j, inner_step diff --git a/flang/test/Lower/do_concurrent_local_default_init.f90 b/flang/test/Lower/do_concurrent_local_default_init.f90 index 7652e4fcd0402..207704ac1a990 100644 --- a/flang/test/Lower/do_concurrent_local_default_init.f90 +++ b/flang/test/Lower/do_concurrent_local_default_init.f90 @@ -29,7 +29,7 @@ subroutine test_default_init() ! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>>>> {fir.bindc_name = "p"}) { ! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_0]] : !fir.ref>>>> ! CHECK: %[[VAL_7:.*]] = fir.box_elesize %[[VAL_6]] : (!fir.box>>>) -> index -! CHECK: fir.do_loop +! CHECK: fir.do_concurrent.loop ! CHECK: %[[VAL_16:.*]] = fir.alloca !fir.box>>> {bindc_name = "p", pinned, uniq_name = "_QFtest_ptrEp"} ! CHECK: %[[VAL_17:.*]] = fir.zero_bits !fir.ptr>> ! CHECK: %[[VAL_18:.*]] = arith.constant 0 : index @@ -43,7 +43,7 @@ subroutine test_default_init() ! CHECK: } ! CHECK-LABEL: func.func @_QPtest_default_init( -! CHECK: fir.do_loop +! CHECK: fir.do_concurrent.loop ! CHECK: %[[VAL_26:.*]] = fir.alloca !fir.type<_QFtest_default_initTt{i:i32}> {bindc_name = "a", pinned, uniq_name = "_QFtest_default_initEa"} ! CHECK: %[[VAL_27:.*]] = fir.embox %[[VAL_26]] : (!fir.ref>) -> !fir.box> ! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_27]] : (!fir.box>) -> !fir.box diff --git a/flang/test/Lower/loops.f90 b/flang/test/Lower/loops.f90 index ea65ba3e4d66d..60df27a591dc3 100644 --- a/flang/test/Lower/loops.f90 +++ b/flang/test/Lower/loops.f90 @@ -2,15 +2,6 @@ ! CHECK-LABEL: loop_test subroutine loop_test - ! CHECK: %[[VAL_2:.*]] = fir.alloca i16 {bindc_name = "i"} - ! CHECK: %[[VAL_3:.*]] = fir.alloca i16 {bindc_name = "i"} - ! CHECK: %[[VAL_4:.*]] = fir.alloca i16 {bindc_name = "i"} - ! CHECK: %[[VAL_5:.*]] = fir.alloca i8 {bindc_name = "k"} - ! CHECK: %[[VAL_6:.*]] = fir.alloca i8 {bindc_name = "j"} - ! CHECK: %[[VAL_7:.*]] = fir.alloca i8 {bindc_name = "i"} - ! CHECK: %[[VAL_8:.*]] = fir.alloca i32 {bindc_name = "k"} - ! CHECK: %[[VAL_9:.*]] = fir.alloca i32 {bindc_name = "j"} - ! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i"} ! CHECK: %[[VAL_11:.*]] = fir.alloca !fir.array<5x5x5xi32> {bindc_name = "a", uniq_name = "_QFloop_testEa"} ! CHECK: %[[VAL_12:.*]] = fir.alloca i32 {bindc_name = "asum", uniq_name = "_QFloop_testEasum"} ! CHECK: %[[VAL_13:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFloop_testEi"} @@ -25,7 +16,7 @@ subroutine loop_test j = 200 k = 300 - ! CHECK-COUNT-3: fir.do_loop {{.*}} unordered + ! CHECK: fir.do_concurrent.loop (%{{.*}}, %{{.*}}, %{{.*}}) = {{.*}} do concurrent (i=1:5, j=1:5, k=1:5) ! shared(a) ! CHECK: fir.coordinate_of a(i,j,k) = 0 @@ -33,7 +24,7 @@ subroutine loop_test ! CHECK: fir.call @_FortranAioBeginExternalListOutput print*, 'A:', i, j, k - ! CHECK-COUNT-3: fir.do_loop {{.*}} unordered + ! CHECK: fir.do_concurrent.loop (%{{.*}}, %{{.*}}, %{{.*}}) = {{.*}} ! CHECK: fir.if do concurrent (integer(1)::i=1:5, j=1:5, k=1:5, i.ne.j .and. k.ne.3) shared(a) ! CHECK-COUNT-2: fir.coordinate_of @@ -53,7 +44,7 @@ subroutine loop_test ! CHECK: fir.call @_FortranAioBeginExternalListOutput print*, 'B:', i, j, k, '-', asum - ! CHECK: fir.do_loop {{.*}} unordered + ! CHECK: fir.do_concurrent.loop (%{{.*}}) = {{.*}} ! CHECK-COUNT-2: fir.if do concurrent (integer(2)::i=1:5, i.ne.3) if (i.eq.2 .or. i.eq.4) goto 5 ! fir.if @@ -62,7 +53,7 @@ subroutine loop_test 5 continue enddo - ! CHECK: fir.do_loop {{.*}} unordered + ! CHECK: fir.do_concurrent.loop (%{{.*}}) = {{.*}} ! CHECK-COUNT-2: fir.if do concurrent (integer(2)::i=1:5, i.ne.3) if (i.eq.2 .or. i.eq.4) then ! fir.if @@ -93,10 +84,6 @@ end subroutine loop_test ! CHECK-LABEL: c.func @_QPlis subroutine lis(n) - ! CHECK-DAG: fir.alloca i32 {bindc_name = "m"} - ! CHECK-DAG: fir.alloca i32 {bindc_name = "j"} - ! CHECK-DAG: fir.alloca i32 {bindc_name = "i"} - ! CHECK-DAG: fir.alloca i8 {bindc_name = "i"} ! CHECK-DAG: fir.alloca i32 {bindc_name = "j", uniq_name = "_QFlisEj"} ! CHECK-DAG: fir.alloca i32 {bindc_name = "k", uniq_name = "_QFlisEk"} ! CHECK-DAG: fir.alloca !fir.box>> {bindc_name = "p", uniq_name = "_QFlisEp"} @@ -117,8 +104,8 @@ subroutine lis(n) ! CHECK: } r = 0 - ! CHECK: fir.do_loop %arg1 = %{{.*}} to %{{.*}} step %{{.*}} unordered { - ! CHECK: fir.do_loop %arg2 = %{{.*}} to %{{.*}} step %c1{{.*}} iter_args(%arg3 = %{{.*}}) -> (index, i32) { + ! CHECK: fir.do_concurrent { + ! CHECK: fir.do_concurrent.loop (%{{.*}}) = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) { ! CHECK: } ! CHECK: } do concurrent (integer(kind=1)::i=n:1:-1) @@ -128,16 +115,18 @@ subroutine lis(n) enddo enddo - ! CHECK: fir.do_loop %arg1 = %{{.*}} to %{{.*}} step %c1{{.*}} unordered { - ! CHECK: fir.do_loop %arg2 = %{{.*}} to %{{.*}} step %c1{{.*}} unordered { + ! CHECK: fir.do_concurrent.loop (%{{.*}}, %{{.*}}) = (%{{.*}}, %{{.*}}) to (%{{.*}}, %{{.*}}) step (%{{.*}}, %{{.*}}) { ! CHECK: fir.if %{{.*}} { ! CHECK: %[[V_95:[0-9]+]] = fir.alloca !fir.array, %{{.*}}, %{{.*}} {bindc_name = "t", pinned, uniq_name = "_QFlisEt"} ! CHECK: %[[V_96:[0-9]+]] = fir.alloca !fir.box>> {bindc_name = "p", pinned, uniq_name = "_QFlisEp"} ! CHECK: fir.store %{{.*}} to %[[V_96]] : !fir.ref>>> ! CHECK: fir.do_loop %arg3 = %{{.*}} to %{{.*}} step %c1{{.*}} iter_args(%arg4 = %{{.*}}) -> (index, i32) { - ! CHECK: fir.do_loop %arg5 = %{{.*}} to %{{.*}} step %c1{{.*}} unordered { - ! CHECK: fir.load %[[V_96]] : !fir.ref>>> - ! CHECK: fir.convert %[[V_95]] : (!fir.ref>) -> !fir.ref> + ! CHECK: fir.do_concurrent { + ! CHECK: fir.alloca i32 {bindc_name = "m"} + ! CHECK: fir.do_concurrent.loop (%{{.*}}) = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) { + ! CHECK: fir.load %[[V_96]] : !fir.ref>>> + ! CHECK: fir.convert %[[V_95]] : (!fir.ref>) -> !fir.ref> + ! CHECK: } ! CHECK: } ! CHECK: } ! CHECK: fir.convert %[[V_95]] : (!fir.ref>) -> !fir.ref> diff --git a/flang/test/Lower/loops3.f90 b/flang/test/Lower/loops3.f90 index 78f39e1013082..84db1972cca16 100644 --- a/flang/test/Lower/loops3.f90 +++ b/flang/test/Lower/loops3.f90 @@ -12,9 +12,7 @@ subroutine loop_test ! CHECK: %[[VAL_0:.*]] = fir.alloca f32 {bindc_name = "m", uniq_name = "_QFloop_testEm"} ! CHECK: %[[VAL_1:.*]] = fir.address_of(@_QFloop_testEsum) : !fir.ref - ! CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} unordered reduce(#fir.reduce_attr -> %[[VAL_1:.*]] : !fir.ref, #fir.reduce_attr -> %[[VAL_0:.*]] : !fir.ref) { - ! CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} unordered reduce(#fir.reduce_attr -> %[[VAL_1:.*]] : !fir.ref, #fir.reduce_attr -> %[[VAL_0:.*]] : !fir.ref) { - ! CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} unordered reduce(#fir.reduce_attr -> %[[VAL_1:.*]] : !fir.ref, #fir.reduce_attr -> %[[VAL_0:.*]] : !fir.ref) { + ! CHECK: fir.do_concurrent.loop ({{.*}}) = ({{.*}}) to ({{.*}}) step ({{.*}}) reduce(#fir.reduce_attr -> %[[VAL_1:.*]] : !fir.ref, #fir.reduce_attr -> %[[VAL_0:.*]] : !fir.ref) { do concurrent (i=1:5, j=1:5, k=1:5) local(tmp) reduce(+:sum) reduce(max:m) tmp = i + j + k sum = tmp + sum diff --git a/flang/test/Lower/nsw.f90 b/flang/test/Lower/nsw.f90 index 4ee9e5da829e6..2ec1efb2af42a 100644 --- a/flang/test/Lower/nsw.f90 +++ b/flang/test/Lower/nsw.f90 @@ -139,7 +139,6 @@ subroutine loop_params3(a,lb,ub,st) ! CHECK-LABEL: func.func @_QPloop_params3( ! CHECK: %[[VAL_4:.*]] = arith.constant 2 : i32 ! CHECK: %[[VAL_5:.*]] = arith.constant 1 : i32 -! CHECK: %[[VAL_9:.*]] = fir.declare %{{.*}}i"} : (!fir.ref) -> !fir.ref ! CHECK: %[[VAL_11:.*]] = fir.declare %{{.*}}lb"} : (!fir.ref, !fir.dscope) -> !fir.ref ! CHECK: %[[VAL_12:.*]] = fir.declare %{{.*}}ub"} : (!fir.ref, !fir.dscope) -> !fir.ref ! CHECK: %[[VAL_14:.*]] = fir.declare %{{.*}}i"} : (!fir.ref) -> !fir.ref @@ -153,4 +152,6 @@ subroutine loop_params3(a,lb,ub,st) ! CHECK: %[[VAL_31:.*]] = fir.load %[[VAL_15]] : !fir.ref ! CHECK: %[[VAL_32:.*]] = arith.muli %[[VAL_31]], %[[VAL_4]] overflow : i32 ! CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (i32) -> index -! CHECK: fir.do_loop %[[VAL_34:.*]] = %[[VAL_28]] to %[[VAL_30]] step %[[VAL_33]] unordered { +! CHECK: fir.do_concurrent { +! CHECK: %[[VAL_9:.*]] = fir.declare %{{.*}}i"} : (!fir.ref) -> !fir.ref +! CHECK: fir.do_concurrent.loop (%[[VAL_34:.*]]) = (%[[VAL_28]]) to (%[[VAL_30]]) step (%[[VAL_33]]) { diff --git a/flang/test/Transforms/DoConcurrent/basic_host.f90 b/flang/test/Transforms/DoConcurrent/basic_host.f90 index 12f63031cbaee..b84d4481ac766 100644 --- a/flang/test/Transforms/DoConcurrent/basic_host.f90 +++ b/flang/test/Transforms/DoConcurrent/basic_host.f90 @@ -1,3 +1,6 @@ +! Fails until we update the pass to use the `fir.do_concurrent` op. +! XFAIL: * + ! Tests mapping of a basic `do concurrent` loop to `!$omp parallel do`. ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fdo-concurrent-to-openmp=host %s -o - \ diff --git a/flang/test/Transforms/DoConcurrent/locally_destroyed_temp.f90 b/flang/test/Transforms/DoConcurrent/locally_destroyed_temp.f90 index f82696669eca6..4e13c0919589a 100644 --- a/flang/test/Transforms/DoConcurrent/locally_destroyed_temp.f90 +++ b/flang/test/Transforms/DoConcurrent/locally_destroyed_temp.f90 @@ -1,3 +1,6 @@ +! Fails until we update the pass to use the `fir.do_concurrent` op. +! XFAIL: * + ! Tests that "loop-local values" are properly handled by localizing them to the ! body of the loop nest. See `collectLoopLocalValues` and `localizeLoopLocalValue` ! for a definition of "loop-local values" and how they are handled. diff --git a/flang/test/Transforms/DoConcurrent/loop_nest_test.f90 b/flang/test/Transforms/DoConcurrent/loop_nest_test.f90 index 32bed61fe69e4..adc4a488d1ec9 100644 --- a/flang/test/Transforms/DoConcurrent/loop_nest_test.f90 +++ b/flang/test/Transforms/DoConcurrent/loop_nest_test.f90 @@ -1,3 +1,6 @@ +! Fails until we update the pass to use the `fir.do_concurrent` op. +! XFAIL: * + ! Tests loop-nest detection algorithm for do-concurrent mapping. ! REQUIRES: asserts diff --git a/flang/test/Transforms/DoConcurrent/multiple_iteration_ranges.f90 b/flang/test/Transforms/DoConcurrent/multiple_iteration_ranges.f90 index d0210726de83e..26800678d381c 100644 --- a/flang/test/Transforms/DoConcurrent/multiple_iteration_ranges.f90 +++ b/flang/test/Transforms/DoConcurrent/multiple_iteration_ranges.f90 @@ -1,3 +1,6 @@ +! Fails until we update the pass to use the `fir.do_concurrent` op. +! XFAIL: * + ! Tests mapping of a `do concurrent` loop with multiple iteration ranges. ! RUN: split-file %s %t diff --git a/flang/test/Transforms/DoConcurrent/non_const_bounds.f90 b/flang/test/Transforms/DoConcurrent/non_const_bounds.f90 index cd1bd4f98a3f5..23a3aae976c07 100644 --- a/flang/test/Transforms/DoConcurrent/non_const_bounds.f90 +++ b/flang/test/Transforms/DoConcurrent/non_const_bounds.f90 @@ -1,3 +1,6 @@ +! Fails until we update the pass to use the `fir.do_concurrent` op. +! XFAIL: * + ! RUN: %flang_fc1 -emit-hlfir -fopenmp -fdo-concurrent-to-openmp=host %s -o - \ ! RUN: | FileCheck %s diff --git a/flang/test/Transforms/DoConcurrent/not_perfectly_nested.f90 b/flang/test/Transforms/DoConcurrent/not_perfectly_nested.f90 index 184fdfe00d397..d1c02101318ab 100644 --- a/flang/test/Transforms/DoConcurrent/not_perfectly_nested.f90 +++ b/flang/test/Transforms/DoConcurrent/not_perfectly_nested.f90 @@ -1,3 +1,6 @@ +! Fails until we update the pass to use the `fir.do_concurrent` op. +! XFAIL: * + ! Tests that if `do concurrent` is not perfectly nested in its parent loop, that ! we skip converting the not-perfectly nested `do concurrent` loop.