[flang-commits] [llvm] [clang-tools-extra] [lld] [clang] [compiler-rt] [flang] [libc] [lldb] [libcxx] [libcxxabi] [Flang][OpenMP] Handle SECTION construct from within SECTIONS (PR #77759)
Krzysztof Parzyszek via flang-commits
flang-commits at lists.llvm.org
Mon Jan 15 06:38:14 PST 2024
https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/77759
>From 62f31654ec66fe0e2a27200d0484d3c70d4ce2c1 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 20 Dec 2023 15:12:04 -0600
Subject: [PATCH 1/7] [Flang][OpenMP] Separate creation of work-sharing and
SIMD loops, NFC
These two constructs were both handled in `genOMP` for loop constructs.
There is some shared code between the two, but there are also enough
differences to separate these two cases into individual functions.
The shared code may be placed into a helper function later if needed.
Recursive lowering [1/5]
---
flang/lib/Lower/OpenMP.cpp | 252 ++++++++++++++++++++++---------------
1 file changed, 153 insertions(+), 99 deletions(-)
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index c3a570bf15ea0d..350cb29121da93 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -2968,24 +2968,150 @@ genOMP(Fortran::lower::AbstractConverter &converter,
standaloneConstruct.u);
}
-static void genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::pft::Evaluation &eval,
- Fortran::semantics::SemanticsContext &semanticsContext,
- const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
+static void
+createSimdLoop(Fortran::lower::AbstractConverter &converter,
+ Fortran::lower::pft::Evaluation &eval,
+ llvm::omp::Directive ompDirective,
+ const Fortran::parser::OmpClauseList &loopOpClauseList,
+ mlir::Location loc) {
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
- llvm::SmallVector<mlir::Value> lowerBound, upperBound, step, linearVars,
- linearStepVars, reductionVars;
+ DataSharingProcessor dsp(converter, loopOpClauseList, eval);
+ dsp.processStep1();
+
+ Fortran::lower::StatementContext stmtCtx;
mlir::Value scheduleChunkClauseOperand;
- mlir::IntegerAttr orderedClauseOperand;
+ llvm::SmallVector<mlir::Value> lowerBound, upperBound, step, reductionVars;
+ llvm::SmallVector<const Fortran::semantics::Symbol *> iv;
+ llvm::SmallVector<mlir::Attribute> reductionDeclSymbols;
+ mlir::omp::ClauseOrderKindAttr orderClauseOperand;
+ std::size_t loopVarTypeSize;
+
+ ClauseProcessor cp(converter, loopOpClauseList);
+ cp.processCollapse(loc, eval, lowerBound, upperBound, step, iv,
+ loopVarTypeSize);
+ cp.processScheduleChunk(stmtCtx, scheduleChunkClauseOperand);
+ cp.processReduction(loc, reductionVars, reductionDeclSymbols);
+ cp.processTODO<Fortran::parser::OmpClause::Linear,
+ Fortran::parser::OmpClause::Order>(loc, ompDirective);
+
+ // The types of lower bound, upper bound, and step are converted into the
+ // type of the loop variable if necessary.
+ mlir::Type loopVarType = getLoopVarType(converter, loopVarTypeSize);
+ for (unsigned it = 0; it < (unsigned)lowerBound.size(); it++) {
+ lowerBound[it] =
+ firOpBuilder.createConvert(loc, loopVarType, lowerBound[it]);
+ upperBound[it] =
+ firOpBuilder.createConvert(loc, loopVarType, upperBound[it]);
+ step[it] = firOpBuilder.createConvert(loc, loopVarType, step[it]);
+ }
+
+ llvm::SmallVector<mlir::Value> alignedVars, nontemporalVars;
+ mlir::Value ifClauseOperand;
+ mlir::IntegerAttr simdlenClauseOperand, safelenClauseOperand;
+ cp.processIf(Fortran::parser::OmpIfClause::DirectiveNameModifier::Simd,
+ ifClauseOperand);
+ cp.processSimdlen(simdlenClauseOperand);
+ cp.processSafelen(safelenClauseOperand);
+ cp.processTODO<Fortran::parser::OmpClause::Aligned,
+ Fortran::parser::OmpClause::Allocate,
+ Fortran::parser::OmpClause::Nontemporal>(loc, ompDirective);
+
+ mlir::TypeRange resultType;
+ auto simdLoopOp = firOpBuilder.create<mlir::omp::SimdLoopOp>(
+ loc, resultType, lowerBound, upperBound, step, alignedVars,
+ /*alignment_values=*/nullptr, ifClauseOperand, nontemporalVars,
+ orderClauseOperand, simdlenClauseOperand, safelenClauseOperand,
+ /*inclusive=*/firOpBuilder.getUnitAttr());
+ createBodyOfOp<mlir::omp::SimdLoopOp>(simdLoopOp, converter, loc, eval,
+ &loopOpClauseList, iv,
+ /*outer=*/false, &dsp);
+}
+
+static void createWsLoop(Fortran::lower::AbstractConverter &converter,
+ Fortran::lower::pft::Evaluation &eval,
+ llvm::omp::Directive ompDirective,
+ const Fortran::parser::OmpClauseList &beginClauseList,
+ const Fortran::parser::OmpClauseList *endClauseList,
+ mlir::Location loc) {
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+ DataSharingProcessor dsp(converter, beginClauseList, eval);
+ dsp.processStep1();
+
+ Fortran::lower::StatementContext stmtCtx;
+ mlir::Value scheduleChunkClauseOperand;
+ llvm::SmallVector<mlir::Value> lowerBound, upperBound, step, reductionVars,
+ linearVars, linearStepVars;
+ llvm::SmallVector<const Fortran::semantics::Symbol *> iv;
+ llvm::SmallVector<mlir::Attribute> reductionDeclSymbols;
mlir::omp::ClauseOrderKindAttr orderClauseOperand;
mlir::omp::ClauseScheduleKindAttr scheduleValClauseOperand;
- mlir::omp::ScheduleModifierAttr scheduleModClauseOperand;
mlir::UnitAttr nowaitClauseOperand, scheduleSimdClauseOperand;
- llvm::SmallVector<mlir::Attribute> reductionDeclSymbols;
- Fortran::lower::StatementContext stmtCtx;
+ mlir::IntegerAttr orderedClauseOperand;
+ mlir::omp::ScheduleModifierAttr scheduleModClauseOperand;
std::size_t loopVarTypeSize;
- llvm::SmallVector<const Fortran::semantics::Symbol *> iv;
+ ClauseProcessor cp(converter, beginClauseList);
+ cp.processCollapse(loc, eval, lowerBound, upperBound, step, iv,
+ loopVarTypeSize);
+ cp.processScheduleChunk(stmtCtx, scheduleChunkClauseOperand);
+ cp.processReduction(loc, reductionVars, reductionDeclSymbols);
+ cp.processTODO<Fortran::parser::OmpClause::Linear,
+ Fortran::parser::OmpClause::Order>(loc, ompDirective);
+
+ // The types of lower bound, upper bound, and step are converted into the
+ // type of the loop variable if necessary.
+ mlir::Type loopVarType = getLoopVarType(converter, loopVarTypeSize);
+ for (unsigned it = 0; it < (unsigned)lowerBound.size(); it++) {
+ lowerBound[it] =
+ firOpBuilder.createConvert(loc, loopVarType, lowerBound[it]);
+ upperBound[it] =
+ firOpBuilder.createConvert(loc, loopVarType, upperBound[it]);
+ step[it] = firOpBuilder.createConvert(loc, loopVarType, step[it]);
+ }
+
+ auto wsLoopOp = firOpBuilder.create<mlir::omp::WsLoopOp>(
+ loc, lowerBound, upperBound, step, linearVars, linearStepVars,
+ reductionVars,
+ reductionDeclSymbols.empty()
+ ? nullptr
+ : mlir::ArrayAttr::get(firOpBuilder.getContext(),
+ reductionDeclSymbols),
+ scheduleValClauseOperand, scheduleChunkClauseOperand,
+ /*schedule_modifiers=*/nullptr,
+ /*simd_modifier=*/nullptr, nowaitClauseOperand, orderedClauseOperand,
+ orderClauseOperand,
+ /*inclusive=*/firOpBuilder.getUnitAttr());
+
+ // Handle attribute based clauses.
+ if (cp.processOrdered(orderedClauseOperand))
+ wsLoopOp.setOrderedValAttr(orderedClauseOperand);
+
+ if (cp.processSchedule(scheduleValClauseOperand, scheduleModClauseOperand,
+ scheduleSimdClauseOperand)) {
+ wsLoopOp.setScheduleValAttr(scheduleValClauseOperand);
+ wsLoopOp.setScheduleModifierAttr(scheduleModClauseOperand);
+ wsLoopOp.setSimdModifierAttr(scheduleSimdClauseOperand);
+ }
+ // In FORTRAN `nowait` clause occur at the end of `omp do` directive.
+ // i.e
+ // !$omp do
+ // <...>
+ // !$omp end do nowait
+ if (endClauseList) {
+ if (ClauseProcessor(converter, *endClauseList)
+ .processNowait(nowaitClauseOperand))
+ wsLoopOp.setNowaitAttr(nowaitClauseOperand);
+ }
+
+ createBodyOfOp<mlir::omp::WsLoopOp>(wsLoopOp, converter, loc, eval,
+ &beginClauseList, iv,
+ /*outer=*/false, &dsp);
+}
+
+static void genOMP(Fortran::lower::AbstractConverter &converter,
+ Fortran::lower::pft::Evaluation &eval,
+ Fortran::semantics::SemanticsContext &semanticsContext,
+ const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
const auto &beginLoopDirective =
std::get<Fortran::parser::OmpBeginLoopDirective>(loopConstruct.t);
const auto &loopOpClauseList =
@@ -2995,6 +3121,17 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
const auto ompDirective =
std::get<Fortran::parser::OmpLoopDirective>(beginLoopDirective.t).v;
+ const auto *endClauseList = [&]() {
+ using RetTy = const Fortran::parser::OmpClauseList *;
+ if (auto &endLoopDirective =
+ std::get<std::optional<Fortran::parser::OmpEndLoopDirective>>(
+ loopConstruct.t)) {
+ return RetTy(
+ &std::get<Fortran::parser::OmpClauseList>((*endLoopDirective).t));
+ }
+ return RetTy();
+ }();
+
bool validDirective = false;
if (llvm::omp::topTaskloopSet.test(ompDirective)) {
validDirective = true;
@@ -3033,97 +3170,14 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
")");
}
- DataSharingProcessor dsp(converter, loopOpClauseList, eval);
- dsp.processStep1();
-
- ClauseProcessor cp(converter, loopOpClauseList);
- cp.processCollapse(currentLocation, eval, lowerBound, upperBound, step, iv,
- loopVarTypeSize);
- cp.processScheduleChunk(stmtCtx, scheduleChunkClauseOperand);
- cp.processReduction(currentLocation, reductionVars, reductionDeclSymbols);
- cp.processTODO<Fortran::parser::OmpClause::Linear,
- Fortran::parser::OmpClause::Order>(currentLocation,
- ompDirective);
-
- // The types of lower bound, upper bound, and step are converted into the
- // type of the loop variable if necessary.
- mlir::Type loopVarType = getLoopVarType(converter, loopVarTypeSize);
- for (unsigned it = 0; it < (unsigned)lowerBound.size(); it++) {
- lowerBound[it] = firOpBuilder.createConvert(currentLocation, loopVarType,
- lowerBound[it]);
- upperBound[it] = firOpBuilder.createConvert(currentLocation, loopVarType,
- upperBound[it]);
- step[it] =
- firOpBuilder.createConvert(currentLocation, loopVarType, step[it]);
- }
-
// 2.9.3.1 SIMD construct
if (llvm::omp::allSimdSet.test(ompDirective)) {
- llvm::SmallVector<mlir::Value> alignedVars, nontemporalVars;
- mlir::Value ifClauseOperand;
- mlir::IntegerAttr simdlenClauseOperand, safelenClauseOperand;
- cp.processIf(Fortran::parser::OmpIfClause::DirectiveNameModifier::Simd,
- ifClauseOperand);
- cp.processSimdlen(simdlenClauseOperand);
- cp.processSafelen(safelenClauseOperand);
- cp.processTODO<Fortran::parser::OmpClause::Aligned,
- Fortran::parser::OmpClause::Allocate,
- Fortran::parser::OmpClause::Nontemporal>(currentLocation,
- ompDirective);
-
- mlir::TypeRange resultType;
- auto simdLoopOp = firOpBuilder.create<mlir::omp::SimdLoopOp>(
- currentLocation, resultType, lowerBound, upperBound, step, alignedVars,
- /*alignment_values=*/nullptr, ifClauseOperand, nontemporalVars,
- orderClauseOperand, simdlenClauseOperand, safelenClauseOperand,
- /*inclusive=*/firOpBuilder.getUnitAttr());
- createBodyOfOp<mlir::omp::SimdLoopOp>(
- simdLoopOp, converter, currentLocation, eval, &loopOpClauseList, iv,
- /*outer=*/false, &dsp);
- return;
- }
-
- auto wsLoopOp = firOpBuilder.create<mlir::omp::WsLoopOp>(
- currentLocation, lowerBound, upperBound, step, linearVars, linearStepVars,
- reductionVars,
- reductionDeclSymbols.empty()
- ? nullptr
- : mlir::ArrayAttr::get(firOpBuilder.getContext(),
- reductionDeclSymbols),
- scheduleValClauseOperand, scheduleChunkClauseOperand,
- /*schedule_modifiers=*/nullptr,
- /*simd_modifier=*/nullptr, nowaitClauseOperand, orderedClauseOperand,
- orderClauseOperand,
- /*inclusive=*/firOpBuilder.getUnitAttr());
-
- // Handle attribute based clauses.
- if (cp.processOrdered(orderedClauseOperand))
- wsLoopOp.setOrderedValAttr(orderedClauseOperand);
-
- if (cp.processSchedule(scheduleValClauseOperand, scheduleModClauseOperand,
- scheduleSimdClauseOperand)) {
- wsLoopOp.setScheduleValAttr(scheduleValClauseOperand);
- wsLoopOp.setScheduleModifierAttr(scheduleModClauseOperand);
- wsLoopOp.setSimdModifierAttr(scheduleSimdClauseOperand);
- }
- // In FORTRAN `nowait` clause occur at the end of `omp do` directive.
- // i.e
- // !$omp do
- // <...>
- // !$omp end do nowait
- if (const auto &endClauseList =
- std::get<std::optional<Fortran::parser::OmpEndLoopDirective>>(
- loopConstruct.t)) {
- const auto &clauseList =
- std::get<Fortran::parser::OmpClauseList>((*endClauseList).t);
- if (ClauseProcessor(converter, clauseList)
- .processNowait(nowaitClauseOperand))
- wsLoopOp.setNowaitAttr(nowaitClauseOperand);
+ createSimdLoop(converter, eval, ompDirective, loopOpClauseList,
+ currentLocation);
+ } else {
+ createWsLoop(converter, eval, ompDirective, loopOpClauseList, endClauseList,
+ currentLocation);
}
-
- createBodyOfOp<mlir::omp::WsLoopOp>(wsLoopOp, converter, currentLocation,
- eval, &loopOpClauseList, iv,
- /*outer=*/false, &dsp);
}
static void
>From 841ae5f68c36628bf209b220595fcb6e81bad18d Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 9 Jan 2024 12:22:06 -0600
Subject: [PATCH 2/7] [Flang][OpenMP] Push genEval calls to individual
operations, NFC
Introduce `genNestedEvaluations` that will lower all evaluations
nested in the given, accouting for a potential COLLAPSE directive.
Recursive lowering [2/5]
---
flang/lib/Lower/OpenMP.cpp | 115 +++++++++++++++++++------------------
1 file changed, 60 insertions(+), 55 deletions(-)
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index 350cb29121da93..496b4ba27a0533 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -110,6 +110,32 @@ static void gatherFuncAndVarSyms(
}
}
+static Fortran::lower::pft::Evaluation *
+getEvalPastCollapse(Fortran::lower::pft::Evaluation &eval, int collapseValue) {
+ if (collapseValue == 0)
+ return &eval;
+
+ Fortran::lower::pft::Evaluation *curEval = &eval.getFirstNestedEvaluation();
+ for (int i = 1; i < collapseValue; i++) {
+ // The nested evaluations should be DoConstructs (i.e. they should form
+ // a loop nest). Each DoConstruct is a tuple <NonLabelDoStmt, Block,
+ // EndDoStmt>.
+ assert(curEval->isA<Fortran::parser::DoConstruct>());
+ curEval = &*std::next(curEval->getNestedEvaluations().begin());
+ }
+ return curEval;
+}
+
+static void genNestedEvaluations(Fortran::lower::AbstractConverter &converter,
+ Fortran::lower::pft::Evaluation &eval,
+ int collapseValue = 0) {
+ Fortran::lower::pft::Evaluation *curEval =
+ getEvalPastCollapse(eval, collapseValue);
+
+ for (Fortran::lower::pft::Evaluation &e : curEval->getNestedEvaluations())
+ converter.genEval(e);
+}
+
//===----------------------------------------------------------------------===//
// DataSharingProcessor
//===----------------------------------------------------------------------===//
@@ -2944,7 +2970,7 @@ genOmpFlush(Fortran::lower::AbstractConverter &converter,
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
Fortran::semantics::SemanticsContext &semanticsContext,
const Fortran::parser::OpenMPStandaloneConstruct &standaloneConstruct) {
std::visit(
@@ -3025,6 +3051,9 @@ createSimdLoop(Fortran::lower::AbstractConverter &converter,
createBodyOfOp<mlir::omp::SimdLoopOp>(simdLoopOp, converter, loc, eval,
&loopOpClauseList, iv,
/*outer=*/false, &dsp);
+
+ genNestedEvaluations(converter, eval,
+ Fortran::lower::getCollapseValue(loopOpClauseList));
}
static void createWsLoop(Fortran::lower::AbstractConverter &converter,
@@ -3106,9 +3135,13 @@ static void createWsLoop(Fortran::lower::AbstractConverter &converter,
createBodyOfOp<mlir::omp::WsLoopOp>(wsLoopOp, converter, loc, eval,
&beginClauseList, iv,
/*outer=*/false, &dsp);
+
+ genNestedEvaluations(converter, eval,
+ Fortran::lower::getCollapseValue(beginClauseList));
}
static void genOMP(Fortran::lower::AbstractConverter &converter,
+ Fortran::lower::SymMap &symTable,
Fortran::lower::pft::Evaluation &eval,
Fortran::semantics::SemanticsContext &semanticsContext,
const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
@@ -3178,11 +3211,12 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
createWsLoop(converter, eval, ompDirective, loopOpClauseList, endClauseList,
currentLocation);
}
+ genOpenMPReduction(converter, loopOpClauseList);
}
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
Fortran::semantics::SemanticsContext &semanticsContext,
const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
const auto &beginBlockDirective =
@@ -3297,11 +3331,14 @@ genOMP(Fortran::lower::AbstractConverter &converter,
break;
}
}
+
+ genNestedEvaluations(converter, eval);
+ genOpenMPReduction(converter, beginClauseList);
}
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPCriticalConstruct &criticalConstruct) {
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
mlir::Location currentLocation = converter.getCurrentLocation();
@@ -3335,11 +3372,12 @@ genOMP(Fortran::lower::AbstractConverter &converter,
}();
createBodyOfOp<mlir::omp::CriticalOp>(criticalOp, converter, currentLocation,
eval);
+ genNestedEvaluations(converter, eval);
}
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPSectionConstruct §ionConstruct) {
mlir::Location currentLocation = converter.getCurrentLocation();
const Fortran::parser::OpenMPConstruct *parentOmpConstruct =
@@ -3358,14 +3396,17 @@ genOMP(Fortran::lower::AbstractConverter &converter,
.t);
// Currently only private/firstprivate clause is handled, and
// all privatization is done within `omp.section` operations.
+ symTable.pushScope();
genOpWithBody<mlir::omp::SectionOp>(converter, eval, currentLocation,
/*outerCombined=*/false,
§ionsClauseList);
+ genNestedEvaluations(converter, eval);
+ symTable.popScope();
}
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPSectionsConstruct §ionsConstruct) {
mlir::Location currentLocation = converter.getCurrentLocation();
llvm::SmallVector<mlir::Value> allocateOperands, allocatorOperands;
@@ -3405,11 +3446,13 @@ genOMP(Fortran::lower::AbstractConverter &converter,
/*reduction_vars=*/mlir::ValueRange(),
/*reductions=*/nullptr, allocateOperands,
allocatorOperands, nowaitClauseOperand);
+
+ genNestedEvaluations(converter, eval);
}
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPAtomicConstruct &atomicConstruct) {
std::visit(
Fortran::common::visitors{
@@ -3503,6 +3546,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
}
static void genOMP(Fortran::lower::AbstractConverter &converter,
+ Fortran::lower::SymMap &symTable,
Fortran::semantics::SemanticsContext &semanticsContext,
Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPConstruct &ompConstruct) {
@@ -3510,17 +3554,18 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
Fortran::common::visitors{
[&](const Fortran::parser::OpenMPStandaloneConstruct
&standaloneConstruct) {
- genOMP(converter, eval, semanticsContext, standaloneConstruct);
+ genOMP(converter, symTable, eval, semanticsContext,
+ standaloneConstruct);
},
[&](const Fortran::parser::OpenMPSectionsConstruct
§ionsConstruct) {
- genOMP(converter, eval, sectionsConstruct);
+ genOMP(converter, symTable, eval, sectionsConstruct);
},
[&](const Fortran::parser::OpenMPSectionConstruct §ionConstruct) {
- genOMP(converter, eval, sectionConstruct);
+ genOMP(converter, symTable, eval, sectionConstruct);
},
[&](const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
- genOMP(converter, eval, semanticsContext, loopConstruct);
+ genOMP(converter, symTable, eval, semanticsContext, loopConstruct);
},
[&](const Fortran::parser::OpenMPDeclarativeAllocate
&execAllocConstruct) {
@@ -3535,14 +3580,14 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
TODO(converter.getCurrentLocation(), "OpenMPAllocatorsConstruct");
},
[&](const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
- genOMP(converter, eval, semanticsContext, blockConstruct);
+ genOMP(converter, symTable, eval, semanticsContext, blockConstruct);
},
[&](const Fortran::parser::OpenMPAtomicConstruct &atomicConstruct) {
- genOMP(converter, eval, atomicConstruct);
+ genOMP(converter, symTable, eval, atomicConstruct);
},
[&](const Fortran::parser::OpenMPCriticalConstruct
&criticalConstruct) {
- genOMP(converter, eval, criticalConstruct);
+ genOMP(converter, symTable, eval, criticalConstruct);
},
},
ompConstruct.u);
@@ -3606,47 +3651,8 @@ void Fortran::lower::genOpenMPConstruct(
Fortran::semantics::SemanticsContext &semanticsContext,
Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPConstruct &omp) {
-
symTable.pushScope();
- genOMP(converter, semanticsContext, eval, omp);
-
- const Fortran::parser::OpenMPLoopConstruct *ompLoop =
- std::get_if<Fortran::parser::OpenMPLoopConstruct>(&omp.u);
- const Fortran::parser::OpenMPBlockConstruct *ompBlock =
- std::get_if<Fortran::parser::OpenMPBlockConstruct>(&omp.u);
-
- // If loop is part of an OpenMP Construct then the OpenMP dialect
- // workshare loop operation has already been created. Only the
- // body needs to be created here and the do_loop can be skipped.
- // Skip the number of collapsed loops, which is 1 when there is a
- // no collapse requested.
-
- Fortran::lower::pft::Evaluation *curEval = &eval;
- const Fortran::parser::OmpClauseList *loopOpClauseList = nullptr;
- if (ompLoop) {
- loopOpClauseList = &std::get<Fortran::parser::OmpClauseList>(
- std::get<Fortran::parser::OmpBeginLoopDirective>(ompLoop->t).t);
- int64_t collapseValue = Fortran::lower::getCollapseValue(*loopOpClauseList);
-
- curEval = &curEval->getFirstNestedEvaluation();
- for (int64_t i = 1; i < collapseValue; i++) {
- curEval = &*std::next(curEval->getNestedEvaluations().begin());
- }
- }
-
- for (Fortran::lower::pft::Evaluation &e : curEval->getNestedEvaluations())
- converter.genEval(e);
-
- if (ompLoop) {
- genOpenMPReduction(converter, *loopOpClauseList);
- } else if (ompBlock) {
- const auto &blockStart =
- std::get<Fortran::parser::OmpBeginBlockDirective>(ompBlock->t);
- const auto &blockClauses =
- std::get<Fortran::parser::OmpClauseList>(blockStart.t);
- genOpenMPReduction(converter, blockClauses);
- }
-
+ genOMP(converter, symTable, semanticsContext, eval, omp);
symTable.popScope();
}
@@ -3655,8 +3661,7 @@ void Fortran::lower::genOpenMPDeclarativeConstruct(
Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPDeclarativeConstruct &omp) {
genOMP(converter, eval, omp);
- for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations())
- converter.genEval(e);
+ genNestedEvaluations(converter, eval);
}
void Fortran::lower::genOpenMPSymbolProperties(
>From 67ea0e5df3c4919030c963c969d8f9cda0b5996b Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 9 Jan 2024 12:25:10 -0600
Subject: [PATCH 3/7] [Flang][OpenMP] Handle SECTION construct from within
SECTIONS
Introduce `createSectionOp`, invoke it from the SECTIONS construct for
each nested SECTION construct. This makes it unnecessary to embed
OpenMPSectionConstruct inside of OpenMPSectionConstruct anymore.
Recursive lowering [3/5]
---
flang/lib/Lower/OpenMP.cpp | 57 +++++++++++++++++---------------------
1 file changed, 26 insertions(+), 31 deletions(-)
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index 496b4ba27a0533..aa315d7ab280e2 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -2379,6 +2379,18 @@ genParallelOp(Fortran::lower::AbstractConverter &converter,
procBindKindAttr);
}
+static mlir::omp::SectionOp
+genSectionOp(Fortran::lower::AbstractConverter &converter,
+ Fortran::lower::pft::Evaluation &eval,
+ mlir::Location currentLocation,
+ const Fortran::parser::OmpClauseList §ionsClauseList) {
+ // Currently only private/firstprivate clause is handled, and
+ // all privatization is done within `omp.section` operations.
+ return genOpWithBody<mlir::omp::SectionOp>(converter, eval, currentLocation,
+ /*outerCombined=*/false,
+ §ionsClauseList);
+}
+
static mlir::omp::SingleOp
genSingleOp(Fortran::lower::AbstractConverter &converter,
Fortran::lower::pft::Evaluation &eval,
@@ -3375,35 +3387,6 @@ genOMP(Fortran::lower::AbstractConverter &converter,
genNestedEvaluations(converter, eval);
}
-static void
-genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
- const Fortran::parser::OpenMPSectionConstruct §ionConstruct) {
- mlir::Location currentLocation = converter.getCurrentLocation();
- const Fortran::parser::OpenMPConstruct *parentOmpConstruct =
- eval.parentConstruct->getIf<Fortran::parser::OpenMPConstruct>();
- assert(parentOmpConstruct &&
- "No enclosing parent OpenMPConstruct on SECTION construct");
- const Fortran::parser::OpenMPSectionsConstruct *sectionsConstruct =
- std::get_if<Fortran::parser::OpenMPSectionsConstruct>(
- &parentOmpConstruct->u);
- assert(sectionsConstruct && "SECTION construct must have parent"
- "SECTIONS construct");
- const Fortran::parser::OmpClauseList §ionsClauseList =
- std::get<Fortran::parser::OmpClauseList>(
- std::get<Fortran::parser::OmpBeginSectionsDirective>(
- sectionsConstruct->t)
- .t);
- // Currently only private/firstprivate clause is handled, and
- // all privatization is done within `omp.section` operations.
- symTable.pushScope();
- genOpWithBody<mlir::omp::SectionOp>(converter, eval, currentLocation,
- /*outerCombined=*/false,
- §ionsClauseList);
- genNestedEvaluations(converter, eval);
- symTable.popScope();
-}
-
static void
genOMP(Fortran::lower::AbstractConverter &converter,
Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
@@ -3447,7 +3430,18 @@ genOMP(Fortran::lower::AbstractConverter &converter,
/*reductions=*/nullptr, allocateOperands,
allocatorOperands, nowaitClauseOperand);
- genNestedEvaluations(converter, eval);
+ const auto §ionBlocks =
+ std::get<Fortran::parser::OmpSectionBlocks>(sectionsConstruct.t);
+ auto &firOpBuilder = converter.getFirOpBuilder();
+ auto ip = firOpBuilder.saveInsertionPoint();
+ for (const auto &[nblock, neval] :
+ llvm::zip(sectionBlocks.v, eval.getNestedEvaluations())) {
+ symTable.pushScope();
+ genSectionOp(converter, neval, currentLocation, sectionsClauseList);
+ genNestedEvaluations(converter, neval);
+ symTable.popScope();
+ firOpBuilder.restoreInsertionPoint(ip);
+ }
}
static void
@@ -3562,7 +3556,8 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
genOMP(converter, symTable, eval, sectionsConstruct);
},
[&](const Fortran::parser::OpenMPSectionConstruct §ionConstruct) {
- genOMP(converter, symTable, eval, sectionConstruct);
+ // SECTION constructs are handled as a part of SECTIONS.
+ llvm_unreachable("Unexpected standalone OMP SECTION");
},
[&](const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
genOMP(converter, symTable, eval, semanticsContext, loopConstruct);
>From 8733efcdb1162ad404d4034f39281d4d9b4176e9 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Fri, 12 Jan 2024 18:26:06 -0600
Subject: [PATCH 4/7] Rename `getEvalPastCollapse` to `getCollapsedEval`
---
flang/lib/Lower/OpenMP.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index 496b4ba27a0533..91ec4c8f3e1d89 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -111,7 +111,9 @@ static void gatherFuncAndVarSyms(
}
static Fortran::lower::pft::Evaluation *
-getEvalPastCollapse(Fortran::lower::pft::Evaluation &eval, int collapseValue) {
+getCollapsedEval(Fortran::lower::pft::Evaluation &eval, int collapseValue) {
+ // Return the Evaluation of the innermost collapsed loop, or the current
+ // evaluation, if there is nothing to collapse.
if (collapseValue == 0)
return &eval;
@@ -130,7 +132,7 @@ static void genNestedEvaluations(Fortran::lower::AbstractConverter &converter,
Fortran::lower::pft::Evaluation &eval,
int collapseValue = 0) {
Fortran::lower::pft::Evaluation *curEval =
- getEvalPastCollapse(eval, collapseValue);
+ getCollapsedEval(eval, collapseValue);
for (Fortran::lower::pft::Evaluation &e : curEval->getNestedEvaluations())
converter.genEval(e);
>From ffda6b216b11aeb2b4ea9ba7bea1f2207e09a11e Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Fri, 12 Jan 2024 18:27:00 -0600
Subject: [PATCH 5/7] Add symbol table parameter to remaining `genOMP`
functions
---
flang/lib/Lower/OpenMP.cpp | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index 91ec4c8f3e1d89..7ecfac09fd3228 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -3497,6 +3497,7 @@ genOMP(Fortran::lower::AbstractConverter &converter,
}
static void genOMP(Fortran::lower::AbstractConverter &converter,
+ Fortran::lower::SymMap &symTable,
Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPDeclareTargetConstruct
&declareTargetConstruct) {
@@ -3597,7 +3598,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPDeclarativeConstruct &ompDeclConstruct) {
std::visit(
Fortran::common::visitors{
@@ -3616,7 +3617,7 @@ genOMP(Fortran::lower::AbstractConverter &converter,
},
[&](const Fortran::parser::OpenMPDeclareTargetConstruct
&declareTargetConstruct) {
- genOMP(converter, eval, declareTargetConstruct);
+ genOMP(converter, symTable, eval, declareTargetConstruct);
},
[&](const Fortran::parser::OpenMPRequiresConstruct
&requiresConstruct) {
@@ -3660,9 +3661,9 @@ void Fortran::lower::genOpenMPConstruct(
void Fortran::lower::genOpenMPDeclarativeConstruct(
Fortran::lower::AbstractConverter &converter,
- Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPDeclarativeConstruct &omp) {
- genOMP(converter, eval, omp);
+ genOMP(converter, symTable, eval, omp);
genNestedEvaluations(converter, eval);
}
>From 0d9755dac3f457bc5d42cd9a175f9cf2a9dcd03b Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Fri, 12 Jan 2024 19:24:46 -0600
Subject: [PATCH 6/7] Make all `genOMP` functions have the same interface
---
flang/include/flang/Lower/OpenMP.h | 5 ++-
flang/lib/Lower/Bridge.cpp | 3 +-
flang/lib/Lower/OpenMP.cpp | 56 ++++++++++++++++++++----------
3 files changed, 44 insertions(+), 20 deletions(-)
diff --git a/flang/include/flang/Lower/OpenMP.h b/flang/include/flang/Lower/OpenMP.h
index 6e772c43d8c46e..872b7d50c3e7a8 100644
--- a/flang/include/flang/Lower/OpenMP.h
+++ b/flang/include/flang/Lower/OpenMP.h
@@ -56,7 +56,10 @@ void genOpenMPTerminator(fir::FirOpBuilder &, mlir::Operation *,
void genOpenMPConstruct(AbstractConverter &, Fortran::lower::SymMap &,
semantics::SemanticsContext &, pft::Evaluation &,
const parser::OpenMPConstruct &);
-void genOpenMPDeclarativeConstruct(AbstractConverter &, pft::Evaluation &,
+void genOpenMPDeclarativeConstruct(AbstractConverter &,
+ Fortran::lower::SymMap &,
+ semantics::SemanticsContext &,
+ pft::Evaluation &,
const parser::OpenMPDeclarativeConstruct &);
/// Symbols in OpenMP code can have flags (e.g. threadprivate directive)
/// that require additional handling when lowering the corresponding
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 2bceee09b4f0f2..8006b9b426f4dc 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2440,7 +2440,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
ompDeviceCodeFound =
ompDeviceCodeFound ||
Fortran::lower::isOpenMPDeviceDeclareTarget(*this, getEval(), ompDecl);
- genOpenMPDeclarativeConstruct(*this, getEval(), ompDecl);
+ genOpenMPDeclarativeConstruct(
+ *this, localSymbols, bridge.getSemanticsContext(), getEval(), ompDecl);
builder->restoreInsertionPoint(insertPt);
}
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index fb684b0bae40bd..94c2c78be5be99 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -2972,8 +2972,9 @@ genOmpFlush(Fortran::lower::AbstractConverter &converter,
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable,
Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPStandaloneConstruct &standaloneConstruct) {
std::visit(
Fortran::common::visitors{
@@ -3145,8 +3146,8 @@ static void createWsLoop(Fortran::lower::AbstractConverter &converter,
static void genOMP(Fortran::lower::AbstractConverter &converter,
Fortran::lower::SymMap &symTable,
- Fortran::lower::pft::Evaluation &eval,
Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
const auto &beginLoopDirective =
std::get<Fortran::parser::OmpBeginLoopDirective>(loopConstruct.t);
@@ -3220,8 +3221,9 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable,
Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
const auto &beginBlockDirective =
std::get<Fortran::parser::OmpBeginBlockDirective>(blockConstruct.t);
@@ -3342,7 +3344,9 @@ genOMP(Fortran::lower::AbstractConverter &converter,
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable,
+ Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPCriticalConstruct &criticalConstruct) {
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
mlir::Location currentLocation = converter.getCurrentLocation();
@@ -3381,7 +3385,9 @@ genOMP(Fortran::lower::AbstractConverter &converter,
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable,
+ Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPSectionConstruct §ionConstruct) {
mlir::Location currentLocation = converter.getCurrentLocation();
const Fortran::parser::OpenMPConstruct *parentOmpConstruct =
@@ -3410,7 +3416,9 @@ genOMP(Fortran::lower::AbstractConverter &converter,
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable,
+ Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPSectionsConstruct §ionsConstruct) {
mlir::Location currentLocation = converter.getCurrentLocation();
llvm::SmallVector<mlir::Value> allocateOperands, allocatorOperands;
@@ -3456,7 +3464,9 @@ genOMP(Fortran::lower::AbstractConverter &converter,
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable,
+ Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPAtomicConstruct &atomicConstruct) {
std::visit(
Fortran::common::visitors{
@@ -3500,6 +3510,7 @@ genOMP(Fortran::lower::AbstractConverter &converter,
static void genOMP(Fortran::lower::AbstractConverter &converter,
Fortran::lower::SymMap &symTable,
+ Fortran::semantics::SemanticsContext &semanticsContext,
Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPDeclareTargetConstruct
&declareTargetConstruct) {
@@ -3559,18 +3570,20 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
Fortran::common::visitors{
[&](const Fortran::parser::OpenMPStandaloneConstruct
&standaloneConstruct) {
- genOMP(converter, symTable, eval, semanticsContext,
+ genOMP(converter, symTable, semanticsContext, eval,
standaloneConstruct);
},
[&](const Fortran::parser::OpenMPSectionsConstruct
§ionsConstruct) {
- genOMP(converter, symTable, eval, sectionsConstruct);
+ genOMP(converter, symTable, semanticsContext, eval,
+ sectionsConstruct);
},
[&](const Fortran::parser::OpenMPSectionConstruct §ionConstruct) {
- genOMP(converter, symTable, eval, sectionConstruct);
+ genOMP(converter, symTable, semanticsContext, eval,
+ sectionConstruct);
},
[&](const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
- genOMP(converter, symTable, eval, semanticsContext, loopConstruct);
+ genOMP(converter, symTable, semanticsContext, eval, loopConstruct);
},
[&](const Fortran::parser::OpenMPDeclarativeAllocate
&execAllocConstruct) {
@@ -3585,14 +3598,16 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
TODO(converter.getCurrentLocation(), "OpenMPAllocatorsConstruct");
},
[&](const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
- genOMP(converter, symTable, eval, semanticsContext, blockConstruct);
+ genOMP(converter, symTable, semanticsContext, eval, blockConstruct);
},
[&](const Fortran::parser::OpenMPAtomicConstruct &atomicConstruct) {
- genOMP(converter, symTable, eval, atomicConstruct);
+ genOMP(converter, symTable, semanticsContext, eval,
+ atomicConstruct);
},
[&](const Fortran::parser::OpenMPCriticalConstruct
&criticalConstruct) {
- genOMP(converter, symTable, eval, criticalConstruct);
+ genOMP(converter, symTable, semanticsContext, eval,
+ criticalConstruct);
},
},
ompConstruct.u);
@@ -3600,7 +3615,9 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
static void
genOMP(Fortran::lower::AbstractConverter &converter,
- Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable,
+ Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPDeclarativeConstruct &ompDeclConstruct) {
std::visit(
Fortran::common::visitors{
@@ -3619,7 +3636,8 @@ genOMP(Fortran::lower::AbstractConverter &converter,
},
[&](const Fortran::parser::OpenMPDeclareTargetConstruct
&declareTargetConstruct) {
- genOMP(converter, symTable, eval, declareTargetConstruct);
+ genOMP(converter, symTable, semanticsContext, eval,
+ declareTargetConstruct);
},
[&](const Fortran::parser::OpenMPRequiresConstruct
&requiresConstruct) {
@@ -3663,9 +3681,11 @@ void Fortran::lower::genOpenMPConstruct(
void Fortran::lower::genOpenMPDeclarativeConstruct(
Fortran::lower::AbstractConverter &converter,
- Fortran::lower::SymMap &symTable, Fortran::lower::pft::Evaluation &eval,
+ Fortran::lower::SymMap &symTable,
+ Fortran::semantics::SemanticsContext &semanticsContext,
+ Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPDeclarativeConstruct &omp) {
- genOMP(converter, symTable, eval, omp);
+ genOMP(converter, symTable, semanticsContext, eval, omp);
genNestedEvaluations(converter, eval);
}
More information about the flang-commits
mailing list