[MLIR][OpenMP] Attribute to include WsLoop upperbound

This patch adds an attribute `inclusive` which if present causes
the upperbound to be included in the loop iteration interval.

Reviewed By: ftynse
Differential Revision: https://reviews.llvm.org/D94235
This commit is contained in:
Kiran Chandramohan
2021-01-07 15:51:55 +00:00
parent 4a582d766a
commit 268ff38a71
4 changed files with 45 additions and 11 deletions

View File

@@ -122,7 +122,9 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments]> {
The workshare loop construct specifies that the iterations of the loop(s)
will be executed in parallel by threads in the current context. These
iterations are spread across threads that already exist in the enclosing
parallel region.
parallel region. The lower and upper bounds specify a half-open range: the
range includes the lower bound but does not include the upper bound. If the
`inclusive` attribute is specified then the upper bound is also included.
The body region can contain any number of blocks. The region is terminated
by "omp.yield" instruction without operands.
@@ -174,9 +176,10 @@ def WsLoopOp : OpenMP_Op<"wsloop", [AttrSizedOperandSegments]> {
OptionalAttr<ScheduleKind>:$schedule_val,
Optional<AnyType>:$schedule_chunk_var,
Confined<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$collapse_val,
OptionalAttr<UnitAttr>:$nowait,
UnitAttr:$nowait,
Confined<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$ordered_val,
OptionalAttr<OrderKind>:$order_val);
OptionalAttr<OrderKind>:$order_val,
UnitAttr:$inclusive);
let builders = [
OpBuilderDAG<(ins "ValueRange":$lowerBound, "ValueRange":$upperBound,

View File

@@ -386,7 +386,8 @@ void WsLoopOp::build(OpBuilder &builder, OperationState &state,
/*linear_vars=*/ValueRange(), /*linear_step_vars=*/ValueRange(),
/*schedule_val=*/nullptr, /*schedule_chunk_var=*/nullptr,
/*collapse_val=*/nullptr,
/*nowait=*/nullptr, /*ordered_val=*/nullptr, /*order_val=*/nullptr);
/*nowait=*/false, /*ordered_val=*/nullptr, /*order_val=*/nullptr,
/*inclusive=*/false);
state.addAttributes(attributes);
}

View File

@@ -590,13 +590,12 @@ LogicalResult ModuleTranslation::convertOmpWsLoop(Operation &opInst,
// Delegate actual loop construction to the OpenMP IRBuilder.
// TODO: this currently assumes WsLoop is semantically similar to SCF loop,
// i.e. it has a positive step, uses signed integer semantics, and its upper
// bound is not included. Reconsider this code when WsLoop clearly supports
// more cases.
// i.e. it has a positive step, uses signed integer semantics. Reconsider
// this code when WsLoop clearly supports more cases.
llvm::BasicBlock *insertBlock = builder.GetInsertBlock();
llvm::CanonicalLoopInfo *loopInfo = ompBuilder->createCanonicalLoop(
ompLoc, bodyGen, lowerBound, upperBound, step, /*IsSigned=*/true,
/*InclusiveStop=*/false);
/*InclusiveStop=*/loop.inclusive());
if (failed(bodyGenStatus))
return failure();
@@ -606,9 +605,8 @@ LogicalResult ModuleTranslation::convertOmpWsLoop(Operation &opInst,
// Put them at the start of the current block for now.
llvm::OpenMPIRBuilder::InsertPointTy allocaIP(
insertBlock, insertBlock->getFirstInsertionPt());
loopInfo = ompBuilder->createStaticWorkshareLoop(
ompLoc, loopInfo, allocaIP,
!loop.nowait().hasValue() || loop.nowait().getValue(), chunk);
loopInfo = ompBuilder->createStaticWorkshareLoop(ompLoc, loopInfo, allocaIP,
!loop.nowait(), chunk);
// Continue building IR after the loop.
builder.restoreIP(loopInfo->getAfterIP());

View File

@@ -323,3 +323,35 @@ llvm.func @wsloop_simple(%arg0: !llvm.ptr<float>) {
}
llvm.return
}
// CHECK-LABEL: @wsloop_inclusive_1
llvm.func @wsloop_inclusive_1(%arg0: !llvm.ptr<float>) {
%0 = llvm.mlir.constant(42 : index) : !llvm.i64
%1 = llvm.mlir.constant(10 : index) : !llvm.i64
%2 = llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK: store i64 31, i64* %{{.*}}upperbound
"omp.wsloop"(%1, %0, %2) ( {
^bb0(%arg1: !llvm.i64):
%3 = llvm.mlir.constant(2.000000e+00 : f32) : !llvm.float
%4 = llvm.getelementptr %arg0[%arg1] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
llvm.store %3, %4 : !llvm.ptr<float>
omp.yield
}) {operand_segment_sizes = dense<[1, 1, 1, 0, 0, 0, 0, 0, 0]> : vector<9xi32>} : (!llvm.i64, !llvm.i64, !llvm.i64) -> ()
llvm.return
}
// CHECK-LABEL: @wsloop_inclusive_2
llvm.func @wsloop_inclusive_2(%arg0: !llvm.ptr<float>) {
%0 = llvm.mlir.constant(42 : index) : !llvm.i64
%1 = llvm.mlir.constant(10 : index) : !llvm.i64
%2 = llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK: store i64 32, i64* %{{.*}}upperbound
"omp.wsloop"(%1, %0, %2) ( {
^bb0(%arg1: !llvm.i64):
%3 = llvm.mlir.constant(2.000000e+00 : f32) : !llvm.float
%4 = llvm.getelementptr %arg0[%arg1] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
llvm.store %3, %4 : !llvm.ptr<float>
omp.yield
}) {inclusive, operand_segment_sizes = dense<[1, 1, 1, 0, 0, 0, 0, 0, 0]> : vector<9xi32>} : (!llvm.i64, !llvm.i64, !llvm.i64) -> ()
llvm.return
}