Skip to content

Commit 0326e2d

Browse files
committed
[MLIR][OpenMP] Make omp.simdloop into a loop wrapper
This patch updates the definition of `omp.simdloop` to enforce the restrictions of a wrapper operation. It has been renamed to `omp.simd`, to better reflect the naming used in the spec. Some changes to Flang lowering and OpenMP to LLVM IR translation are introduced in order for this patch to be able to compile and run. The eventual long term solution might be different. This is a WIP posted early for visibility. Related unit tests need updating and there might still be some bugs due to lack of testing.
1 parent 99e8123 commit 0326e2d

File tree

5 files changed

+101
-99
lines changed

5 files changed

+101
-99
lines changed

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ struct OpWithBodyGenInfo {
521521
/// \param [in] op - the operation the body belongs to.
522522
/// \param [in] info - options controlling code-gen for the construction.
523523
template <typename Op>
524-
static void createBodyOfOp(Op &op, OpWithBodyGenInfo &info) {
524+
static void createBodyOfOp(mlir::Operation &op, OpWithBodyGenInfo &info) {
525525
fir::FirOpBuilder &firOpBuilder = info.converter.getFirOpBuilder();
526526

527527
auto insertMarker = [](fir::FirOpBuilder &builder) {
@@ -537,10 +537,10 @@ static void createBodyOfOp(Op &op, OpWithBodyGenInfo &info) {
537537
auto regionArgs =
538538
[&]() -> llvm::SmallVector<const Fortran::semantics::Symbol *> {
539539
if (info.genRegionEntryCB != nullptr) {
540-
return info.genRegionEntryCB(op);
540+
return info.genRegionEntryCB(&op);
541541
}
542542

543-
firOpBuilder.createBlock(&op.getRegion());
543+
firOpBuilder.createBlock(&op.getRegion(0));
544544
return {};
545545
}();
546546
// Mark the earliest insertion point.
@@ -556,7 +556,7 @@ static void createBodyOfOp(Op &op, OpWithBodyGenInfo &info) {
556556
// Start with privatization, so that the lowering of the nested
557557
// code will use the right symbols.
558558
constexpr bool isLoop = std::is_same_v<Op, mlir::omp::WsloopOp> ||
559-
std::is_same_v<Op, mlir::omp::SimdLoopOp>;
559+
std::is_same_v<Op, mlir::omp::SimdOp>;
560560
bool privatize = info.clauses && !info.outerCombined;
561561

562562
firOpBuilder.setInsertionPoint(marker);
@@ -582,9 +582,9 @@ static void createBodyOfOp(Op &op, OpWithBodyGenInfo &info) {
582582
// a lot of complications for our approach if the terminator generation
583583
// is delayed past this point. Insert a temporary terminator here, then
584584
// delete it.
585-
firOpBuilder.setInsertionPointToEnd(&op.getRegion().back());
586-
auto *temp = Fortran::lower::genOpenMPTerminator(
587-
firOpBuilder, op.getOperation(), info.loc);
585+
firOpBuilder.setInsertionPointToEnd(&op.getRegion(0).back());
586+
auto *temp =
587+
Fortran::lower::genOpenMPTerminator(firOpBuilder, &op, info.loc);
588588
firOpBuilder.setInsertionPointAfter(marker);
589589
genNestedEvaluations(info.converter, info.eval);
590590
temp->erase();
@@ -626,10 +626,10 @@ static void createBodyOfOp(Op &op, OpWithBodyGenInfo &info) {
626626
return exit;
627627
};
628628

629-
if (auto *exitBlock = getUniqueExit(op.getRegion())) {
629+
if (auto *exitBlock = getUniqueExit(op.getRegion(0))) {
630630
firOpBuilder.setInsertionPointToEnd(exitBlock);
631-
auto *term = Fortran::lower::genOpenMPTerminator(
632-
firOpBuilder, op.getOperation(), info.loc);
631+
auto *term =
632+
Fortran::lower::genOpenMPTerminator(firOpBuilder, &op, info.loc);
633633
// Only insert lastprivate code when there actually is an exit block.
634634
// Such a block may not exist if the nested code produced an infinite
635635
// loop (this may not make sense in production code, but a user could
@@ -638,11 +638,11 @@ static void createBodyOfOp(Op &op, OpWithBodyGenInfo &info) {
638638
if (privatize) {
639639
if (!info.dsp) {
640640
assert(tempDsp.has_value());
641-
tempDsp->processStep2(op, isLoop);
641+
tempDsp->processStep2(&op, isLoop);
642642
} else {
643643
if (isLoop && regionArgs.size() > 0)
644644
info.dsp->setLoopIV(info.converter.getSymbolAddress(*regionArgs[0]));
645-
info.dsp->processStep2(op, isLoop);
645+
info.dsp->processStep2(&op, isLoop);
646646
}
647647
}
648648
}
@@ -719,7 +719,7 @@ template <typename OpTy, typename... Args>
719719
static OpTy genOpWithBody(OpWithBodyGenInfo &info, Args &&...args) {
720720
auto op = info.converter.getFirOpBuilder().create<OpTy>(
721721
info.loc, std::forward<Args>(args)...);
722-
createBodyOfOp<OpTy>(op, info);
722+
createBodyOfOp<OpTy>(*op, info);
723723
return op;
724724
}
725725

@@ -1720,11 +1720,20 @@ createSimdLoop(Fortran::lower::AbstractConverter &converter,
17201720
cp.processTODO<clause::Aligned, clause::Allocate, clause::Linear,
17211721
clause::Nontemporal, clause::Order>(loc, ompDirective);
17221722

1723+
// Create omp.simd wrapper.
17231724
mlir::TypeRange resultType;
1724-
auto simdLoopOp = firOpBuilder.create<mlir::omp::SimdLoopOp>(
1725-
loc, resultType, lowerBound, upperBound, step, alignedVars,
1726-
/*alignment_values=*/nullptr, ifClauseOperand, nontemporalVars,
1727-
orderClauseOperand, simdlenClauseOperand, safelenClauseOperand,
1725+
auto simdOp = firOpBuilder.create<mlir::omp::SimdOp>(
1726+
loc, resultType, alignedVars, /*alignment_values=*/nullptr,
1727+
ifClauseOperand, nontemporalVars, orderClauseOperand,
1728+
simdlenClauseOperand, safelenClauseOperand);
1729+
1730+
firOpBuilder.createBlock(&simdOp.getRegion());
1731+
firOpBuilder.setInsertionPoint(
1732+
Fortran::lower::genOpenMPTerminator(firOpBuilder, simdOp, loc));
1733+
1734+
// Create nested omp.loop_nest and fill body with loop contents.
1735+
auto loopOp = firOpBuilder.create<mlir::omp::LoopNestOp>(
1736+
loc, lowerBound, upperBound, step,
17281737
/*inclusive=*/firOpBuilder.getUnitAttr());
17291738

17301739
auto *nestedEval = getCollapsedLoopEval(
@@ -1734,11 +1743,11 @@ createSimdLoop(Fortran::lower::AbstractConverter &converter,
17341743
return genLoopVars(op, converter, loc, iv);
17351744
};
17361745

1737-
createBodyOfOp<mlir::omp::SimdLoopOp>(
1738-
simdLoopOp, OpWithBodyGenInfo(converter, semaCtx, loc, *nestedEval)
1739-
.setClauses(&loopOpClauseList)
1740-
.setDataSharingProcessor(&dsp)
1741-
.setGenRegionEntryCb(ivCallback));
1746+
createBodyOfOp<mlir::omp::SimdOp>(
1747+
*loopOp, OpWithBodyGenInfo(converter, semaCtx, loc, *nestedEval)
1748+
.setClauses(&loopOpClauseList)
1749+
.setDataSharingProcessor(&dsp)
1750+
.setGenRegionEntryCb(ivCallback));
17421751
}
17431752

17441753
static void createWsloop(Fortran::lower::AbstractConverter &converter,
@@ -1819,11 +1828,11 @@ static void createWsloop(Fortran::lower::AbstractConverter &converter,
18191828
};
18201829

18211830
createBodyOfOp<mlir::omp::WsloopOp>(
1822-
wsLoopOp, OpWithBodyGenInfo(converter, semaCtx, loc, *nestedEval)
1823-
.setClauses(&beginClauseList)
1824-
.setDataSharingProcessor(&dsp)
1825-
.setReductions(&reductionSymbols, &reductionTypes)
1826-
.setGenRegionEntryCb(ivCallback));
1831+
*wsLoopOp, OpWithBodyGenInfo(converter, semaCtx, loc, *nestedEval)
1832+
.setClauses(&beginClauseList)
1833+
.setDataSharingProcessor(&dsp)
1834+
.setReductions(&reductionSymbols, &reductionTypes)
1835+
.setGenRegionEntryCb(ivCallback));
18271836
}
18281837

18291838
static void createSimdWsloop(
@@ -2200,7 +2209,7 @@ genOMP(Fortran::lower::AbstractConverter &converter,
22002209
global.getSymName()));
22012210
}();
22022211
auto genInfo = OpWithBodyGenInfo(converter, semaCtx, currentLocation, eval);
2203-
createBodyOfOp<mlir::omp::CriticalOp>(criticalOp, genInfo);
2212+
createBodyOfOp<mlir::omp::CriticalOp>(*criticalOp, genInfo);
22042213
}
22052214

22062215
static void
@@ -2410,10 +2419,9 @@ mlir::Operation *Fortran::lower::genOpenMPTerminator(fir::FirOpBuilder &builder,
24102419
mlir::Operation *op,
24112420
mlir::Location loc) {
24122421
if (mlir::isa<mlir::omp::WsloopOp, mlir::omp::DeclareReductionOp,
2413-
mlir::omp::AtomicUpdateOp, mlir::omp::SimdLoopOp>(op))
2422+
mlir::omp::AtomicUpdateOp>(op))
24142423
return builder.create<mlir::omp::YieldOp>(loc);
2415-
else
2416-
return builder.create<mlir::omp::TerminatorOp>(loc);
2424+
return builder.create<mlir::omp::TerminatorOp>(loc);
24172425
}
24182426

24192427
void Fortran::lower::genOpenMPConstruct(

mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ def LoopNestOp : OpenMP_Op<"loop_nest", [SameVariadicOperandSize,
549549
loop operations intended to serve as a stopgap solution until the long-term
550550
representation of canonical loops is defined. Specifically, this operation
551551
is intended to serve as a unique source for loop information during the
552-
transition to making `omp.distribute`, `omp.simdloop`, `omp.taskloop` and
552+
transition to making `omp.distribute`, `omp.simd`, `omp.taskloop` and
553553
`omp.wsloop` wrapper operations. It is not intended to help with the
554554
addition of support for loop transformations, non-rectangular loops and
555555
non-perfectly nested loops.
@@ -704,24 +704,19 @@ def WsloopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments,
704704
// Simd construct [2.9.3.1]
705705
//===----------------------------------------------------------------------===//
706706

707-
def SimdLoopOp : OpenMP_Op<"simdloop", [AttrSizedOperandSegments,
708-
AllTypesMatch<["lowerBound", "upperBound", "step"]>,
709-
DeclareOpInterfaceMethods<LoopWrapperInterface>,
710-
RecursiveMemoryEffects]> {
711-
let summary = "simd loop construct";
707+
def SimdOp : OpenMP_Op<"simd", [AttrSizedOperandSegments,
708+
DeclareOpInterfaceMethods<LoopWrapperInterface>,
709+
RecursiveMemoryEffects,
710+
SingleBlockImplicitTerminator<"TerminatorOp">]> {
711+
let summary = "simd construct";
712712
let description = [{
713713
The simd construct can be applied to a loop to indicate that the loop can be
714714
transformed into a SIMD loop (that is, multiple iterations of the loop can
715-
be executed concurrently using SIMD instructions).. The lower and upper
716-
bounds specify a half-open range: the range includes the lower bound but
717-
does not include the upper bound. If the `inclusive` attribute is specified
718-
then the upper bound is also included.
719-
720-
The body region can contain any number of blocks. The region is terminated
721-
by "omp.yield" instruction without operands.
715+
be executed concurrently using SIMD instructions).
722716

723-
Collapsed loops are represented by the simd-loop having a list of indices,
724-
bounds and steps where the size of the list is equal to the collapse value.
717+
The body region can contain a single block which must contain a single
718+
operation and a terminator. The operation must be another compatible loop
719+
wrapper or an `omp.loop_nest`.
725720

726721
The `alignment_values` attribute additionally specifies alignment of each
727722
corresponding aligned operand. Note that `$aligned_vars` and
@@ -745,26 +740,26 @@ def SimdLoopOp : OpenMP_Op<"simdloop", [AttrSizedOperandSegments,
745740
SIMD chunk can have a distance in the logical iteration space that is
746741
greater than or equal to the value given in the clause.
747742
```
748-
omp.simdloop <clauses>
749-
for (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) {
750-
// block operations
751-
omp.yield
743+
omp.simd <clauses> {
744+
omp.loop_nest (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) {
745+
%a = load %arrA[%i1, %i2] : memref<?x?xf32>
746+
%b = load %arrB[%i1, %i2] : memref<?x?xf32>
747+
%sum = arith.addf %a, %b : f32
748+
store %sum, %arrC[%i1, %i2] : memref<?x?xf32>
749+
omp.yield
750+
}
752751
}
753752
```
754753
}];
755754

756755
// TODO: Add other clauses
757-
let arguments = (ins Variadic<IntLikeType>:$lowerBound,
758-
Variadic<IntLikeType>:$upperBound,
759-
Variadic<IntLikeType>:$step,
760-
Variadic<OpenMP_PointerLikeType>:$aligned_vars,
756+
let arguments = (ins Variadic<OpenMP_PointerLikeType>:$aligned_vars,
761757
OptionalAttr<I64ArrayAttr>:$alignment_values,
762758
Optional<I1>:$if_expr,
763759
Variadic<OpenMP_PointerLikeType>:$nontemporal_vars,
764760
OptionalAttr<OrderKindAttr>:$order_val,
765761
ConfinedAttr<OptionalAttr<I64Attr>, [IntPositive]>:$simdlen,
766-
ConfinedAttr<OptionalAttr<I64Attr>, [IntPositive]>:$safelen,
767-
UnitAttr:$inclusive
762+
ConfinedAttr<OptionalAttr<I64Attr>, [IntPositive]>:$safelen
768763
);
769764

770765
let regions = (region AnyRegion:$region);
@@ -777,14 +772,7 @@ def SimdLoopOp : OpenMP_Op<"simdloop", [AttrSizedOperandSegments,
777772
|`order` `(` custom<ClauseAttr>($order_val) `)`
778773
|`simdlen` `(` $simdlen `)`
779774
|`safelen` `(` $safelen `)`
780-
) `for` custom<LoopControl>($region, $lowerBound, $upperBound, $step,
781-
type($step), $inclusive) attr-dict
782-
}];
783-
784-
let extraClassDeclaration = [{
785-
/// Returns the number of loops in the simd loop nest.
786-
unsigned getNumLoops() { return getLowerBound().size(); }
787-
775+
) $region attr-dict
788776
}];
789777

790778
let hasCustomAssemblyFormat = 1;
@@ -795,7 +783,7 @@ def SimdLoopOp : OpenMP_Op<"simdloop", [AttrSizedOperandSegments,
795783
def YieldOp : OpenMP_Op<"yield",
796784
[Pure, ReturnLike, Terminator,
797785
ParentOneOf<["LoopNestOp", "WsloopOp", "DeclareReductionOp",
798-
"AtomicUpdateOp", "SimdLoopOp", "PrivateClauseOp"]>]> {
786+
"AtomicUpdateOp", "PrivateClauseOp"]>]> {
799787
let summary = "loop yield and termination operation";
800788
let description = [{
801789
"omp.yield" yields SSA values from the OpenMP dialect op region and

mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -252,18 +252,18 @@ void mlir::configureOpenMPToLLVMConversionLegality(
252252
target.addDynamicallyLegalOp<
253253
mlir::omp::AtomicUpdateOp, mlir::omp::CriticalOp, mlir::omp::TargetOp,
254254
mlir::omp::TargetDataOp, mlir::omp::OrderedRegionOp,
255-
mlir::omp::ParallelOp, mlir::omp::WsloopOp, mlir::omp::SimdLoopOp,
255+
mlir::omp::ParallelOp, mlir::omp::WsloopOp, mlir::omp::SimdOp,
256256
mlir::omp::MasterOp, mlir::omp::SectionOp, mlir::omp::SectionsOp,
257257
mlir::omp::SingleOp, mlir::omp::TaskgroupOp, mlir::omp::TaskOp,
258-
mlir::omp::DeclareReductionOp,
259-
mlir::omp::PrivateClauseOp>([&](Operation *op) {
260-
return std::all_of(op->getRegions().begin(), op->getRegions().end(),
261-
[&](Region &region) {
262-
return typeConverter.isLegal(&region);
263-
}) &&
264-
typeConverter.isLegal(op->getOperandTypes()) &&
265-
typeConverter.isLegal(op->getResultTypes());
266-
});
258+
mlir::omp::DeclareReductionOp, mlir::omp::PrivateClauseOp>(
259+
[&](Operation *op) {
260+
return std::all_of(op->getRegions().begin(), op->getRegions().end(),
261+
[&](Region &region) {
262+
return typeConverter.isLegal(&region);
263+
}) &&
264+
typeConverter.isLegal(op->getOperandTypes()) &&
265+
typeConverter.isLegal(op->getResultTypes());
266+
});
267267
}
268268

269269
void mlir::populateOpenMPToLLVMConversionPatterns(LLVMTypeConverter &converter,
@@ -282,7 +282,7 @@ void mlir::populateOpenMPToLLVMConversionPatterns(LLVMTypeConverter &converter,
282282
ReductionOpConversion, RegionOpConversion<omp::OrderedRegionOp>,
283283
RegionOpConversion<omp::ParallelOp>, RegionOpConversion<omp::WsloopOp>,
284284
RegionOpConversion<omp::SectionsOp>, RegionOpConversion<omp::SectionOp>,
285-
RegionOpConversion<omp::SimdLoopOp>, RegionOpConversion<omp::SingleOp>,
285+
RegionOpConversion<omp::SimdOp>, RegionOpConversion<omp::SingleOp>,
286286
RegionOpConversion<omp::TaskgroupOp>, RegionOpConversion<omp::TaskOp>,
287287
RegionOpConversion<omp::TargetDataOp>, RegionOpConversion<omp::TargetOp>,
288288
RegionLessOpWithVarOperandsConversion<omp::AtomicWriteOp>,

mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,10 +1484,7 @@ void printLoopControl(OpAsmPrinter &p, Operation *op, Region &region,
14841484
// Verifier for Simd construct [2.9.3.1]
14851485
//===----------------------------------------------------------------------===//
14861486

1487-
LogicalResult SimdLoopOp::verify() {
1488-
if (this->getLowerBound().empty()) {
1489-
return emitOpError() << "empty lowerbound for simd loop operation";
1490-
}
1487+
LogicalResult SimdOp::verify() {
14911488
if (this->getSimdlen().has_value() && this->getSafelen().has_value() &&
14921489
this->getSimdlen().value() > this->getSafelen().value()) {
14931490
return emitOpError()
@@ -1500,6 +1497,13 @@ LogicalResult SimdLoopOp::verify() {
15001497
return failure();
15011498
if (verifyNontemporalClause(*this, this->getNontemporalVars()).failed())
15021499
return failure();
1500+
1501+
if (!isWrapper())
1502+
return emitOpError() << "must be a loop wrapper";
1503+
1504+
if (getNestedWrapper())
1505+
return emitOpError() << "must wrap an 'omp.loop_nest' directly";
1506+
15031507
return success();
15041508
}
15051509

0 commit comments

Comments
 (0)