Skip to content

[MLIR][OpenMP] Update op verifiers dependent on omp.wsloop (2/5) #89211

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

Merged
merged 11 commits into from
Apr 24, 2024
72 changes: 49 additions & 23 deletions mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1964,21 +1964,51 @@ LogicalResult CriticalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
// Ordered construct
//===----------------------------------------------------------------------===//

static LogicalResult verifyOrderedParent(Operation &op) {
bool hasRegion = op.getNumRegions() > 0;
auto loopOp = op.getParentOfType<LoopNestOp>();
if (!loopOp) {
if (hasRegion)
return success();

// TODO: Consider if this needs to be the case only for the standalone
// variant of the ordered construct.
return op.emitOpError() << "must be nested inside of a loop";
}

Operation *wrapper = loopOp->getParentOp();
if (auto wsloopOp = dyn_cast<WsloopOp>(wrapper)) {
IntegerAttr orderedAttr = wsloopOp.getOrderedValAttr();
if (!orderedAttr)
return op.emitOpError() << "the enclosing worksharing-loop region must "
"have an ordered clause";

if (hasRegion && orderedAttr.getInt() != 0)
return op.emitOpError() << "the enclosing loop's ordered clause must not "
"have a parameter present";

if (!hasRegion && orderedAttr.getInt() == 0)
return op.emitOpError() << "the enclosing loop's ordered clause must "
"have a parameter present";
} else if (!isa<SimdOp>(wrapper)) {
return op.emitOpError() << "must be nested inside of a worksharing, simd "
"or worksharing simd loop";
}
return success();
}

void OrderedOp::build(OpBuilder &builder, OperationState &state,
const OrderedOpClauseOps &clauses) {
OrderedOp::build(builder, state, clauses.doacrossDependTypeAttr,
clauses.doacrossNumLoopsAttr, clauses.doacrossVectorVars);
}

LogicalResult OrderedOp::verify() {
auto container = (*this)->getParentOfType<WsloopOp>();
if (!container || !container.getOrderedValAttr() ||
container.getOrderedValAttr().getInt() == 0)
return emitOpError() << "ordered depend directive must be closely "
<< "nested inside a worksharing-loop with ordered "
<< "clause with parameter present";

if (container.getOrderedValAttr().getInt() != (int64_t)*getNumLoopsVal())
if (failed(verifyOrderedParent(**this)))
return failure();

auto wrapper = (*this)->getParentOfType<WsloopOp>();
if (!wrapper || *wrapper.getOrderedVal() != *getNumLoopsVal())
return emitOpError() << "number of variables in depend clause does not "
<< "match number of iteration variables in the "
<< "doacross loop";
Expand All @@ -1996,15 +2026,7 @@ LogicalResult OrderedRegionOp::verify() {
if (getSimd())
return failure();

if (auto container = (*this)->getParentOfType<WsloopOp>()) {
if (!container.getOrderedValAttr() ||
container.getOrderedValAttr().getInt() != 0)
return emitOpError() << "ordered region must be closely nested inside "
<< "a worksharing-loop region with an ordered "
<< "clause without parameter present";
}

return success();
return verifyOrderedParent(**this);
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -2149,15 +2171,19 @@ LogicalResult CancelOp::verify() {
<< "inside a parallel region";
}
if (cct == ClauseCancellationConstructType::Loop) {
if (!isa<WsloopOp>(parentOp)) {
return emitOpError() << "cancel loop must appear "
<< "inside a worksharing-loop region";
auto loopOp = dyn_cast<LoopNestOp>(parentOp);
auto wsloopOp = llvm::dyn_cast_if_present<WsloopOp>(
loopOp ? loopOp->getParentOp() : nullptr);

if (!wsloopOp) {
return emitOpError()
<< "cancel loop must appear inside a worksharing-loop region";
}
if (cast<WsloopOp>(parentOp).getNowaitAttr()) {
if (wsloopOp.getNowaitAttr()) {
return emitError() << "A worksharing construct that is canceled "
<< "must not have a nowait clause";
}
if (cast<WsloopOp>(parentOp).getOrderedValAttr()) {
if (wsloopOp.getOrderedValAttr()) {
return emitError() << "A worksharing construct that is canceled "
<< "must not have an ordered clause";
}
Expand Down Expand Up @@ -2195,7 +2221,7 @@ LogicalResult CancellationPointOp::verify() {
<< "inside a parallel region";
}
if ((cct == ClauseCancellationConstructType::Loop) &&
!isa<WsloopOp>(parentOp)) {
(!isa<LoopNestOp>(parentOp) || !isa<WsloopOp>(parentOp->getParentOp()))) {
return emitOpError() << "cancellation point loop must appear "
<< "inside a worksharing-loop region";
}
Expand Down
67 changes: 55 additions & 12 deletions mlir/test/Dialect/OpenMP/invalid.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -748,10 +748,10 @@ omp.critical.declare @mutex hint(invalid_hint)

// -----

func.func @omp_ordered1(%arg1 : i32, %arg2 : i32, %arg3 : i32) -> () {
omp.wsloop ordered(1) {
omp.loop_nest (%0) : i32 = (%arg1) to (%arg2) step (%arg3) {
// expected-error @below {{ordered region must be closely nested inside a worksharing-loop region with an ordered clause without parameter present}}
func.func @omp_ordered_region1(%x : i32) -> () {
omp.distribute {
omp.loop_nest (%i) : i32 = (%x) to (%x) step (%x) {
// expected-error @below {{op must be nested inside of a worksharing, simd or worksharing simd loop}}
omp.ordered.region {
omp.terminator
}
Expand All @@ -764,10 +764,26 @@ func.func @omp_ordered1(%arg1 : i32, %arg2 : i32, %arg3 : i32) -> () {

// -----

func.func @omp_ordered2(%arg1 : i32, %arg2 : i32, %arg3 : i32) -> () {
func.func @omp_ordered_region2(%x : i32) -> () {
omp.wsloop {
omp.loop_nest (%0) : i32 = (%arg1) to (%arg2) step (%arg3) {
// expected-error @below {{ordered region must be closely nested inside a worksharing-loop region with an ordered clause without parameter present}}
omp.loop_nest (%i) : i32 = (%x) to (%x) step (%x) {
// expected-error @below {{the enclosing worksharing-loop region must have an ordered clause}}
omp.ordered.region {
omp.terminator
}
omp.yield
}
omp.terminator
}
return
}

// -----

func.func @omp_ordered_region3(%x : i32) -> () {
omp.wsloop ordered(1) {
omp.loop_nest (%i) : i32 = (%x) to (%x) step (%x) {
// expected-error @below {{the enclosing loop's ordered clause must not have a parameter present}}
omp.ordered.region {
omp.terminator
}
Expand All @@ -780,34 +796,61 @@ func.func @omp_ordered2(%arg1 : i32, %arg2 : i32, %arg3 : i32) -> () {

// -----

func.func @omp_ordered3(%vec0 : i64) -> () {
// expected-error @below {{ordered depend directive must be closely nested inside a worksharing-loop with ordered clause with parameter present}}
func.func @omp_ordered1(%vec0 : i64) -> () {
// expected-error @below {{op must be nested inside of a loop}}
omp.ordered depend_type(dependsink) depend_vec(%vec0 : i64) {num_loops_val = 1 : i64}
return
}

// -----

func.func @omp_ordered2(%arg1 : i32, %arg2 : i32, %arg3 : i32, %vec0 : i64) -> () {
omp.distribute {
omp.loop_nest (%0) : i32 = (%arg1) to (%arg2) step (%arg3) {
// expected-error @below {{op must be nested inside of a worksharing, simd or worksharing simd loop}}
omp.ordered depend_type(dependsink) depend_vec(%vec0 : i64) {num_loops_val = 1 : i64}
omp.yield
}
omp.terminator
}
return
}

// -----

func.func @omp_ordered3(%arg1 : i32, %arg2 : i32, %arg3 : i32, %vec0 : i64) -> () {
omp.wsloop {
omp.loop_nest (%0) : i32 = (%arg1) to (%arg2) step (%arg3) {
// expected-error @below {{the enclosing worksharing-loop region must have an ordered clause}}
omp.ordered depend_type(dependsink) depend_vec(%vec0 : i64) {num_loops_val = 1 : i64}
omp.yield
}
omp.terminator
}
return
}

// -----

func.func @omp_ordered4(%arg1 : i32, %arg2 : i32, %arg3 : i32, %vec0 : i64) -> () {
omp.wsloop ordered(0) {
omp.loop_nest (%0) : i32 = (%arg1) to (%arg2) step (%arg3) {
// expected-error @below {{ordered depend directive must be closely nested inside a worksharing-loop with ordered clause with parameter present}}
// expected-error @below {{the enclosing loop's ordered clause must have a parameter present}}
omp.ordered depend_type(dependsink) depend_vec(%vec0 : i64) {num_loops_val = 1 : i64}

omp.yield
}
omp.terminator
}
return
}

// -----

func.func @omp_ordered5(%arg1 : i32, %arg2 : i32, %arg3 : i32, %vec0 : i64, %vec1 : i64) -> () {
omp.wsloop ordered(1) {
omp.loop_nest (%0) : i32 = (%arg1) to (%arg2) step (%arg3) {
// expected-error @below {{number of variables in depend clause does not match number of iteration variables in the doacross loop}}
omp.ordered depend_type(dependsource) depend_vec(%vec0, %vec1 : i64, i64) {num_loops_val = 2 : i64}

omp.yield
}
omp.terminator
Expand Down
Loading