Skip to content

[flang] Implement !DIR$ IVDEP directive #133728

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion flang/include/flang/Optimizer/Builder/FIRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,8 @@ void genScalarAssignment(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &lhs,
const fir::ExtendedValue &rhs,
bool needFinalization = false,
bool isTemporaryLHS = false);
bool isTemporaryLHS = false,
std::optional<mlir::ArrayAttr> accessGroups = nullptr);

/// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalar derived
/// types. The assignment follows Fortran intrinsic assignment semantic for
Expand Down
24 changes: 12 additions & 12 deletions flang/include/flang/Optimizer/Dialect/FIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@ def fir_LoadOp : fir_OneResultOp<"load", [FirAliasTagOpInterface]> {
}];

let arguments = (ins Arg<AnyReferenceLike, "", [MemRead]>:$memref,
OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa);
OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa,
OptionalAttr<LLVM_AccessGroupArrayAttr>:$accessGroups);

let builders = [OpBuilder<(ins "mlir::Value":$refVal)>,
OpBuilder<(ins "mlir::Type":$resTy, "mlir::Value":$refVal)>];
Expand Down Expand Up @@ -335,8 +336,9 @@ def fir_StoreOp : fir_Op<"store", [FirAliasTagOpInterface]> {
}];

let arguments = (ins AnyType:$value,
Arg<AnyReferenceLike, "", [MemWrite]>:$memref,
OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa);
Arg<AnyReferenceLike, "", [MemWrite]>:$memref,
OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa,
OptionalAttr<LLVM_AccessGroupArrayAttr>:$accessGroups);

let builders = [OpBuilder<(ins "mlir::Value":$value, "mlir::Value":$memref)>];

Expand Down Expand Up @@ -2484,15 +2486,13 @@ def fir_CallOp : fir_Op<"call",
```
}];

let arguments = (ins
OptionalAttr<SymbolRefAttr>:$callee,
Variadic<AnyType>:$args,
OptionalAttr<DictArrayAttr>:$arg_attrs,
OptionalAttr<DictArrayAttr>:$res_attrs,
OptionalAttr<fir_FortranProcedureFlagsAttr>:$procedure_attrs,
DefaultValuedAttr<Arith_FastMathAttr,
"::mlir::arith::FastMathFlags::none">:$fastmath
);
let arguments = (ins OptionalAttr<SymbolRefAttr>:$callee,
Variadic<AnyType>:$args, OptionalAttr<DictArrayAttr>:$arg_attrs,
OptionalAttr<DictArrayAttr>:$res_attrs,
OptionalAttr<fir_FortranProcedureFlagsAttr>:$procedure_attrs,
OptionalAttr<LLVM_AccessGroupArrayAttr>:$accessGroups,
DefaultValuedAttr<Arith_FastMathAttr,
"::mlir::arith::FastMathFlags::none">:$fastmath);
let results = (outs Variadic<AnyType>);

let hasCustomAssemblyFormat = 1;
Expand Down
1 change: 1 addition & 0 deletions flang/include/flang/Optimizer/HLFIR/HLFIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ include "flang/Optimizer/Dialect/FIRAttr.td"
include "flang/Optimizer/Dialect/FortranVariableInterface.td"
include "mlir/Dialect/Arith/IR/ArithBase.td"
include "mlir/Dialect/Arith/IR/ArithOpsInterfaces.td"
include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: What is this needed for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I don't need it ! Sorry

include "mlir/IR/BuiltinAttributes.td"

// Base class for FIR operations.
Expand Down
1 change: 1 addition & 0 deletions flang/include/flang/Parser/dump-parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ class ParseTreeDumper {
NODE(parser, CompilerDirective)
NODE(CompilerDirective, AssumeAligned)
NODE(CompilerDirective, IgnoreTKR)
NODE(CompilerDirective, IVDep)
NODE(CompilerDirective, LoopCount)
NODE(CompilerDirective, NameValue)
NODE(CompilerDirective, Unrecognized)
Expand Down
5 changes: 4 additions & 1 deletion flang/include/flang/Parser/parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -3351,6 +3351,7 @@ struct StmtFunctionStmt {
// !DIR$ name[=value] [, name[=value]]... = can be :
// !DIR$ UNROLL [N]
// !DIR$ UNROLL_AND_JAM [N]
// !DIR$ IVDEP
// !DIR$ <anything else>
struct CompilerDirective {
UNION_CLASS_BOILERPLATE(CompilerDirective);
Expand All @@ -3376,10 +3377,12 @@ struct CompilerDirective {
struct UnrollAndJam {
WRAPPER_CLASS_BOILERPLATE(UnrollAndJam, std::optional<std::uint64_t>);
};
EMPTY_CLASS(IVDep);
EMPTY_CLASS(Unrecognized);
CharBlock source;
std::variant<std::list<IgnoreTKR>, LoopCount, std::list<AssumeAligned>,
VectorAlways, std::list<NameValue>, Unroll, UnrollAndJam, Unrecognized>
VectorAlways, std::list<NameValue>, Unroll, UnrollAndJam, Unrecognized,
IVDep>
u;
};

Expand Down
63 changes: 57 additions & 6 deletions flang/lib/Lower/Bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2046,6 +2046,37 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// so no clean-up needs to be generated for these entities.
}

// Add attribute(s) on operations in fir::DoLoopOp if necessary.
void attachAttributesToDoLoopOperations(fir::DoLoopOp &doLoop) {
if (!doLoop.getOperation())
return;
if (auto loopAnnotAttr = doLoop.getLoopAnnotationAttr()) {
if (loopAnnotAttr.getParallelAccesses().size()) {
mlir::LLVM::AccessGroupAttr accessGroupAttr =
loopAnnotAttr.getParallelAccesses().front();
for (mlir::Block &block : doLoop.getRegion()) {
mlir::ArrayAttr attrs =
mlir::ArrayAttr::get(builder->getContext(), {accessGroupAttr});
for (mlir::Operation &op : block.getOperations()) {
if (fir::StoreOp storeOp = mlir::dyn_cast<fir::StoreOp>(op)) {
storeOp.setAccessGroupsAttr(attrs);
} else if (fir::LoadOp loadOp = mlir::dyn_cast<fir::LoadOp>(op)) {
loadOp.setAccessGroupsAttr(attrs);
} else if (hlfir::AssignOp assignOp =
mlir::dyn_cast<hlfir::AssignOp>(op)) {
// 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);
Comment on lines +2065 to +2070
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tracking everything that could generate a store sounds difficult to maintain in the long term. I wonder if this should instead be added by a pass late in the pipeline after all of these stores have been generated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a pass that checks for all fir.do_loop with the parallelAccesses attribute and do the thing in this code here? It can be done, yes, and it could actually be simpler to manage yes.

} else if (fir::CallOp callOp = mlir::dyn_cast<fir::CallOp>(op)) {
callOp.setAccessGroupsAttr(attrs);
}
}
}
}
}
}
Comment on lines +2050 to +2078
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to go into operations that are nested inside other operations?

subroutine sb(A)
  integer, intent(inout) :: A(:)
  integer :: i
  !dir$ ivdep
  do i=1,100
    if (i .gt. 10) then
      A(i) = A(i) + i
    end if 
  end do
end subroutine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's right ! So I also have to go through the operations in depth

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is walk() what you were looking for?

doLoop.walk([&] (auto *op) {
  if (mlir::isa<StoreOp, LoadOp, CallOp>(op))
    // ...
});

// or
doLoop.walk([&] (hlfir::AssignOp assignOp) {
  // ...
});


/// Generate FIR for a DO construct. There are six variants:
/// - unstructured infinite and while loops
/// - structured and unstructured increment loops
Expand Down Expand Up @@ -2155,6 +2186,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {

// This call may generate a branch in some contexts.
genFIR(endDoEval, unstructuredContext);

// Add attribute(s) on operations in fir::DoLoopOp if necessary
for (IncrementLoopInfo &info : incrementLoopNestInfo)
attachAttributesToDoLoopOperations(info.doLoop);
}

/// Generate FIR to evaluate loop control values (lower, upper and step).
Expand Down Expand Up @@ -2235,22 +2270,28 @@ class FirConverter : public Fortran::lower::AbstractConverter {
{}, {}, {}, {});
}

// Enabling loop vectorization attribute.
mlir::LLVM::LoopVectorizeAttr genLoopVectorizeAttr(bool enable = true) {
mlir::BoolAttr disableAttr =
mlir::BoolAttr::get(builder->getContext(), !enable);
return mlir::LLVM::LoopVectorizeAttr::get(builder->getContext(),
/*disable=*/disableAttr, {}, {},
{}, {}, {}, {});
}

void addLoopAnnotationAttr(
IncrementLoopInfo &info,
llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
mlir::LLVM::LoopVectorizeAttr va;
mlir::LLVM::LoopUnrollAttr ua;
mlir::LLVM::LoopUnrollAndJamAttr uja;
llvm::SmallVector<mlir::LLVM::AccessGroupAttr> aga;
bool has_attrs = false;
for (const auto *dir : dirs) {
Fortran::common::visit(
Fortran::common::visitors{
[&](const Fortran::parser::CompilerDirective::VectorAlways &) {
mlir::BoolAttr falseAttr =
mlir::BoolAttr::get(builder->getContext(), false);
va = mlir::LLVM::LoopVectorizeAttr::get(builder->getContext(),
/*disable=*/falseAttr,
{}, {}, {}, {}, {}, {});
va = genLoopVectorizeAttr();
has_attrs = true;
},
[&](const Fortran::parser::CompilerDirective::Unroll &u) {
Expand All @@ -2261,12 +2302,19 @@ class FirConverter : public Fortran::lower::AbstractConverter {
uja = genLoopUnrollAndJamAttr(u.v);
has_attrs = true;
},
[&](const Fortran::parser::CompilerDirective::IVDep &iv) {
va = genLoopVectorizeAttr();
aga.push_back(
mlir::LLVM::AccessGroupAttr::get(builder->getContext()));
has_attrs = true;
},
[&](const auto &) {}},
dir->u);
}
mlir::LLVM::LoopAnnotationAttr la = mlir::LLVM::LoopAnnotationAttr::get(
builder->getContext(), {}, /*vectorize=*/va, {}, /*unroll*/ ua,
/*unroll_and_jam*/ uja, {}, {}, {}, {}, {}, {}, {}, {}, {}, {});
/*unroll_and_jam*/ uja, {}, {}, {}, {}, {}, {}, {}, {}, {},
/*parallelAccesses*/ aga);
if (has_attrs)
info.doLoop.setLoopAnnotationAttr(la);
}
Expand Down Expand Up @@ -2925,6 +2973,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
[&](const Fortran::parser::CompilerDirective::UnrollAndJam &) {
attachDirectiveToLoop(dir, &eval);
},
[&](const Fortran::parser::CompilerDirective::IVDep &) {
attachDirectiveToLoop(dir, &eval);
},
[&](const auto &) {}},
dir.u);
}
Expand Down
3 changes: 2 additions & 1 deletion flang/lib/Lower/ConvertCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,8 @@ Fortran::lower::genCallOpAndResult(
// Standard procedure call with fir.call.
auto call = builder.create<fir::CallOp>(
loc, funcType.getResults(), funcSymbolAttr, operands,
/*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, procAttrs);
/*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, procAttrs,
/*accessGroups*/ mlir::ArrayAttr{});

callNumResults = call.getNumResults();
if (callNumResults != 0)
Expand Down
15 changes: 8 additions & 7 deletions flang/lib/Optimizer/Builder/FIRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1304,12 +1304,11 @@ fir::ExtendedValue fir::factory::arraySectionElementToExtendedValue(
return fir::factory::componentToExtendedValue(builder, loc, element);
}

void fir::factory::genScalarAssignment(fir::FirOpBuilder &builder,
mlir::Location loc,
const fir::ExtendedValue &lhs,
const fir::ExtendedValue &rhs,
bool needFinalization,
bool isTemporaryLHS) {
void fir::factory::genScalarAssignment(
fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &lhs, const fir::ExtendedValue &rhs,
bool needFinalization, bool isTemporaryLHS,
std::optional<mlir::ArrayAttr> accessGroups) {
assert(lhs.rank() == 0 && rhs.rank() == 0 && "must be scalars");
auto type = fir::unwrapSequenceType(
fir::unwrapPassByRefType(fir::getBase(lhs).getType()));
Expand All @@ -1331,7 +1330,9 @@ void fir::factory::genScalarAssignment(fir::FirOpBuilder &builder,
mlir::Value lhsAddr = fir::getBase(lhs);
rhsVal = builder.createConvert(loc, fir::unwrapRefType(lhsAddr.getType()),
rhsVal);
builder.create<fir::StoreOp>(loc, rhsVal, lhsAddr);
fir::StoreOp store = builder.create<fir::StoreOp>(loc, rhsVal, lhsAddr);
if (accessGroups)
store.setAccessGroupsAttr(*accessGroups);
}
}

Expand Down
16 changes: 15 additions & 1 deletion flang/lib/Optimizer/CodeGen/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,10 @@ struct CallOpConversion : public fir::FIROpConversion<fir::CallOp> {
if (mlir::ArrayAttr resAttrs = call.getResAttrsAttr())
llvmCall.setResAttrsAttr(resAttrs);

if (std::optional<mlir::ArrayAttr> optionalAccessGroups =
call.getAccessGroups())
llvmCall.setAccessGroups(*optionalAccessGroups);

if (memAttr)
llvmCall.setMemoryEffectsAttr(
mlir::cast<mlir::LLVM::MemoryEffectsAttr>(memAttr));
Expand Down Expand Up @@ -3267,6 +3271,11 @@ struct LoadOpConversion : public fir::FIROpConversion<fir::LoadOp> {
loadOp.setTBAATags(*optionalTag);
else
attachTBAATag(loadOp, load.getType(), load.getType(), nullptr);

if (std::optional<mlir::ArrayAttr> optionalAccessGroups =
load.getAccessGroups())
loadOp.setAccessGroups(*optionalAccessGroups);

rewriter.replaceOp(load, loadOp.getResult());
}
return mlir::success();
Expand Down Expand Up @@ -3550,7 +3559,12 @@ struct StoreOpConversion : public fir::FIROpConversion<fir::StoreOp> {
newOp = rewriter.create<mlir::LLVM::MemcpyOp>(
loc, llvmMemref, llvmValue, boxSize, /*isVolatile=*/false);
} else {
newOp = rewriter.create<mlir::LLVM::StoreOp>(loc, llvmValue, llvmMemref);
mlir::LLVM::StoreOp storeOp =
rewriter.create<mlir::LLVM::StoreOp>(loc, llvmValue, llvmMemref);
if (std::optional<mlir::ArrayAttr> optionalAccessGroups =
store.getAccessGroups())
storeOp.setAccessGroups(*optionalAccessGroups);
newOp = storeOp;
}
if (std::optional<mlir::ArrayAttr> optionalTag = store.getTbaa())
newOp.setTBAATags(*optionalTag);
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Optimizer/Dialect/FIROps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3948,7 +3948,7 @@ llvm::LogicalResult fir::StoreOp::verify() {

void fir::StoreOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
mlir::Value value, mlir::Value memref) {
build(builder, result, value, memref, {});
build(builder, result, value, memref, {}, {});
}

//===----------------------------------------------------------------------===//
Expand Down
10 changes: 7 additions & 3 deletions flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,17 @@ class AssignOpConversion : public mlir::OpRewritePattern<hlfir::AssignOp> {
!assignOp.isTemporaryLHS() &&
mlir::isa<fir::RecordType>(fir::getElementTypeOf(lhsExv));

std::optional<mlir::ArrayAttr> accessGroups = nullptr;
if (auto attrs = assignOp.getOperation()->getAttrOfType<mlir::ArrayAttr>(
"access_groups"))
accessGroups = attrs;
// genScalarAssignment() must take care of potential overlap
// between LHS and RHS. Note that the overlap is possible
// also for components of LHS/RHS, and the Assign() runtime
// must take care of it.
fir::factory::genScalarAssignment(builder, loc, lhsExv, rhsExv,
needFinalization,
assignOp.isTemporaryLHS());
fir::factory::genScalarAssignment(
builder, loc, lhsExv, rhsExv, needFinalization,
assignOp.isTemporaryLHS(), accessGroups);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few other places in this file where load and store ops are created, should they also be tagged with the access groups?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. The access group applies on loads and stores from assignments in a loop. But I'll make a new pass on it and add tests in that case if needed.

rewriter.eraseOp(assignOp);
return mlir::success();
Expand Down
3 changes: 2 additions & 1 deletion flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ struct DispatchOpConv : public OpConversionPattern<fir::DispatchOp> {
args.append(dispatch.getArgs().begin(), dispatch.getArgs().end());
rewriter.replaceOpWithNewOp<fir::CallOp>(
dispatch, resTypes, nullptr, args, dispatch.getArgAttrsAttr(),
dispatch.getResAttrsAttr(), dispatch.getProcedureAttrsAttr());
dispatch.getResAttrsAttr(), dispatch.getProcedureAttrsAttr(),
mlir::ArrayAttr{});
return mlir::success();
}

Expand Down
3 changes: 3 additions & 0 deletions flang/lib/Parser/Fortran-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,7 @@ TYPE_PARSER(construct<StatOrErrmsg>("STAT =" >> statVariable) ||
// !DIR$ LOOP COUNT (n1[, n2]...)
// !DIR$ name[=value] [, name[=value]]...
// !DIR$ UNROLL [n]
// !DIR$ IVDEP
// !DIR$ <anything else>
constexpr auto ignore_tkr{
"IGNORE_TKR" >> optionalList(construct<CompilerDirective::IgnoreTKR>(
Expand All @@ -1310,13 +1311,15 @@ constexpr auto unroll{
"UNROLL" >> construct<CompilerDirective::Unroll>(maybe(digitString64))};
constexpr auto unrollAndJam{"UNROLL_AND_JAM" >>
construct<CompilerDirective::UnrollAndJam>(maybe(digitString64))};
constexpr auto ivdep{"IVDEP" >> construct<CompilerDirective::IVDep>()};
TYPE_PARSER(beginDirective >> "DIR$ "_tok >>
sourced((construct<CompilerDirective>(ignore_tkr) ||
construct<CompilerDirective>(loopCount) ||
construct<CompilerDirective>(assumeAligned) ||
construct<CompilerDirective>(vectorAlways) ||
construct<CompilerDirective>(unrollAndJam) ||
construct<CompilerDirective>(unroll) ||
construct<CompilerDirective>(ivdep) ||
construct<CompilerDirective>(
many(construct<CompilerDirective::NameValue>(
name, maybe(("="_tok || ":"_tok) >> digitString64))))) /
Expand Down
1 change: 1 addition & 0 deletions flang/lib/Parser/unparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1855,6 +1855,7 @@ class UnparseVisitor {
Word("!DIR$ UNROLL_AND_JAM");
Walk(" ", unrollAndJam.v);
},
[&](const CompilerDirective::IVDep &) { Word("!DIR$ IVDEP"); },
[&](const CompilerDirective::Unrecognized &) {
Word("!DIR$ ");
Word(x.source.ToString());
Expand Down
6 changes: 5 additions & 1 deletion flang/lib/Semantics/canonicalize-directives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ static bool IsExecutionDirective(const parser::CompilerDirective &dir) {
return std::holds_alternative<parser::CompilerDirective::VectorAlways>(
dir.u) ||
std::holds_alternative<parser::CompilerDirective::Unroll>(dir.u) ||
std::holds_alternative<parser::CompilerDirective::UnrollAndJam>(dir.u);
std::holds_alternative<parser::CompilerDirective::UnrollAndJam>(dir.u) ||
std::holds_alternative<parser::CompilerDirective::IVDep>(dir.u);
}

void CanonicalizationOfDirectives::Post(parser::SpecificationPart &spec) {
Expand Down Expand Up @@ -119,6 +120,9 @@ void CanonicalizationOfDirectives::Post(parser::Block &block) {
[&](parser::CompilerDirective::UnrollAndJam &) {
CheckLoopDirective(*dir, block, it);
},
[&](parser::CompilerDirective::IVDep &) {
CheckLoopDirective(*dir, block, it);
},
[&](auto &) {}},
dir->u);
}
Expand Down
3 changes: 2 additions & 1 deletion flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9573,7 +9573,8 @@ void ResolveNamesVisitor::Post(const parser::AssignedGotoStmt &x) {
void ResolveNamesVisitor::Post(const parser::CompilerDirective &x) {
if (std::holds_alternative<parser::CompilerDirective::VectorAlways>(x.u) ||
std::holds_alternative<parser::CompilerDirective::Unroll>(x.u) ||
std::holds_alternative<parser::CompilerDirective::UnrollAndJam>(x.u)) {
std::holds_alternative<parser::CompilerDirective::UnrollAndJam>(x.u) ||
std::holds_alternative<parser::CompilerDirective::IVDep>(x.u)) {
return;
}
if (const auto *tkr{
Expand Down
Loading