diff --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h index 9933e3ed6c308..404144f11e3df 100644 --- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h +++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h @@ -461,7 +461,8 @@ void genNoAliasArrayAssignment( bool temporaryLHS = false, std::function *combiner = - nullptr); + nullptr, + mlir::ArrayAttr accessGroups = {}); /// Generate an assignment from \p rhs to \p lhs when they are known not to /// alias. Handles both arrays and scalars: for arrays, delegates to @@ -474,15 +475,17 @@ void genNoAliasAssignment( bool temporaryLHS = false, std::function *combiner = - nullptr); + nullptr, + mlir::ArrayAttr accessGroups = {}); inline void genNoAliasAssignment( mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity rhs, hlfir::Entity lhs, bool emitWorkshareLoop, bool temporaryLHS, std::function - combiner) { + combiner, + mlir::ArrayAttr accessGroups = {}) { genNoAliasAssignment(loc, builder, rhs, lhs, emitWorkshareLoop, temporaryLHS, - &combiner); + &combiner, accessGroups); } /// Create a new temporary with the shape and parameters of the provided diff --git a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h index ae471eb0d2e04..b014d925592cb 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h +++ b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h @@ -131,6 +131,11 @@ static constexpr llvm::StringRef getHasLifetimeMarkerAttrName() { return "fir.has_lifetime"; } +/// Attribute to mark the access groups of an operation. +static constexpr llvm::StringRef getAccessGroupsAttrName() { + return "access_groups"; +} + /// Does the function, \p func, have a host-associations tuple argument? /// Some internal procedures may have access to host procedure variables. bool hasHostAssociationArgument(mlir::func::FuncOp func); diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 1f35153928500..cd743cc0b27c6 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -2405,7 +2405,8 @@ class FirConverter : public Fortran::lower::AbstractConverter { // In some loops, the HLFIR AssignOp operation can be translated // into FIR operation(s) containing StoreOp. It is therefore // necessary to forward the AccessGroups attribute. - assignOp.getOperation()->setAttr("access_groups", attrs); + assignOp.getOperation()->setAttr(fir::getAccessGroupsAttrName(), + attrs); } else if (fir::CallOp callOp = mlir::dyn_cast(op)) { callOp.setAccessGroupsAttr(attrs); } diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp index a345dcb86e3d6..133fa17af3f71 100644 --- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp +++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp @@ -1396,23 +1396,33 @@ static void combineAndStoreElement( mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity lhs, hlfir::Entity rhs, bool temporaryLHS, std::function *combiner) { + hlfir::Entity, hlfir::Entity)> *combiner, + mlir::ArrayAttr accessGroups) { hlfir::Entity valueToAssign = hlfir::loadTrivialScalar(loc, builder, rhs); + if (accessGroups) + if (auto load = valueToAssign.getDefiningOp()) + load.setAccessGroupsAttr(accessGroups); if (combiner) { hlfir::Entity lhsValue = hlfir::loadTrivialScalar(loc, builder, lhs); + if (accessGroups) + if (auto load = lhsValue.getDefiningOp()) + load.setAccessGroupsAttr(accessGroups); valueToAssign = (*combiner)(loc, builder, lhsValue, valueToAssign); } - hlfir::AssignOp::create(builder, loc, valueToAssign, lhs, - /*realloc=*/false, - /*keep_lhs_length_if_realloc=*/false, - /*temporary_lhs=*/temporaryLHS); + auto assign = hlfir::AssignOp::create(builder, loc, valueToAssign, lhs, + /*realloc=*/false, + /*keep_lhs_length_if_realloc=*/false, + /*temporary_lhs=*/temporaryLHS); + if (accessGroups) + assign->setAttr(fir::getAccessGroupsAttrName(), accessGroups); } void hlfir::genNoAliasArrayAssignment( mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity rhs, hlfir::Entity lhs, bool emitWorkshareLoop, bool temporaryLHS, std::function *combiner) { + hlfir::Entity, hlfir::Entity)> *combiner, + mlir::ArrayAttr accessGroups) { mlir::OpBuilder::InsertionGuard guard(builder); rhs = hlfir::derefPointersAndAllocatables(loc, builder, rhs); lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs); @@ -1434,22 +1444,24 @@ void hlfir::genNoAliasArrayAssignment( auto lhsArrayElement = hlfir::getElementAt(loc, builder, lhs, loopNest.oneBasedIndices); combineAndStoreElement(loc, builder, lhsArrayElement, rhsArrayElement, - temporaryLHS, combiner); + temporaryLHS, combiner, accessGroups); } void hlfir::genNoAliasAssignment( mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity rhs, hlfir::Entity lhs, bool emitWorkshareLoop, bool temporaryLHS, std::function *combiner) { + hlfir::Entity, hlfir::Entity)> *combiner, + mlir::ArrayAttr accessGroups) { if (lhs.isArray()) { genNoAliasArrayAssignment(loc, builder, rhs, lhs, emitWorkshareLoop, - temporaryLHS, combiner); + temporaryLHS, combiner, accessGroups); return; } rhs = hlfir::derefPointersAndAllocatables(loc, builder, rhs); lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs); - combineAndStoreElement(loc, builder, lhs, rhs, temporaryLHS, combiner); + combineAndStoreElement(loc, builder, lhs, rhs, temporaryLHS, combiner, + accessGroups); } std::pair diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp index a63695f38afc6..13d9fc264b9b8 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp @@ -151,7 +151,7 @@ class AssignOpConversion : public mlir::OpRewritePattern { mlir::ArrayAttr accessGroups; if (auto attrs = assignOp.getOperation()->getAttrOfType( - "access_groups")) + fir::getAccessGroupsAttrName())) accessGroups = attrs; // genScalarAssignment() must take care of potential overlap diff --git a/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp b/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp index 1fc592c7fe522..a6a2eb0cb3c37 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRAssign.cpp @@ -107,8 +107,13 @@ class InlineHLFIRAssignConversion mlir::Location loc = assign->getLoc(); fir::FirOpBuilder builder(rewriter, assign.getOperation()); builder.setInsertionPoint(assign); + mlir::ArrayAttr accessGroups; + if (auto attrs = assign.getOperation()->getAttrOfType( + fir::getAccessGroupsAttrName())) + accessGroups = attrs; hlfir::genNoAliasArrayAssignment( - loc, builder, rhs, lhs, flangomp::shouldUseWorkshareLowering(assign)); + loc, builder, rhs, lhs, flangomp::shouldUseWorkshareLowering(assign), + /*temporaryLHS=*/false, /*combiner=*/nullptr, accessGroups); rewriter.eraseOp(assign); return mlir::success(); } diff --git a/flang/test/Lower/ivdep-array.f90 b/flang/test/Lower/ivdep-array.f90 new file mode 100644 index 0000000000000..d018fbaf81a92 --- /dev/null +++ b/flang/test/Lower/ivdep-array.f90 @@ -0,0 +1,20 @@ +! RUN: %flang_fc1 -emit-fir -O2 %s -o - | FileCheck %s + +! CHECK: #[[ANNOTATION:.*]] = #llvm.loop_annotation +subroutine array_assignment_in_loop(a, b) + real :: a(100,100), b(100,100) + !dir$ ivdep + ! CHECK: fir.do_loop + ! CHECK-SAME: loopAnnotation = #[[ANNOTATION]] + do i=1,100 + ! CHECK: fir.do_loop + ! CHECK: fir.load + ! CHECK-SAME: accessGroups = [#[[GROUP]]] + ! CHECK: fir.store + ! CHECK-SAME: accessGroups = [#[[GROUP]]] + a(i, :) = b(i, :) + ! CHECK: } + ! CHECK: } + ! CHECK: return + end do +end subroutine