diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td --- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td @@ -254,9 +254,23 @@ static StringRef getTileKeyword() { return "tile"; } static StringRef getPrivateKeyword() { return "private"; } static StringRef getReductionKeyword() { return "reduction"; } + bool isAuto() { + UnitAttr isAutoAttr = getAttrOfType(getAutoAttrName()); + return static_cast(isAutoAttr); + } + bool isIndependent() { + UnitAttr isIndependentAttr = + getAttrOfType(getIndependentAttrName()); + return static_cast(isIndependentAttr); + } + bool isSeq() { + UnitAttr isSeqAttr = getAttrOfType(getSeqAttrName()); + return static_cast(isSeqAttr); + } + unsigned getExecutionMapping(); }]; - let verifier = ?; + let verifier = [{ return ::verifyLoopOp(*this); }]; } // Yield operation for the acc.loop and acc.parallel operations. diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp --- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp +++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp @@ -475,6 +475,13 @@ // LoopOp //===----------------------------------------------------------------------===// +unsigned LoopOp::getExecutionMapping() { + IntegerAttr execMapping = + getAttrOfType(getExecutionMappingAttrName()); + return execMapping ? execMapping.getInt() + : static_cast(acc::OpenACCExecMapping::NONE); +} + /// Parse acc.loop operation /// operation := `acc.loop` `gang`? `vector`? `worker`? /// `private` `(` value-list `)`? @@ -562,7 +569,7 @@ reductionOperands, operandTypes, result))) return failure(); - if (executionMapping != 0) + if (executionMapping != acc::OpenACCExecMapping::NONE) result.addAttribute(LoopOp::getExecutionMappingAttrName(), builder.getI64IntegerAttr(executionMapping)); @@ -656,5 +663,29 @@ LoopOp::getOperandSegmentSizeAttr()}); } +static LogicalResult verifyLoopOp(acc::LoopOp loopOp) { + // auto, independent and seq attribute are mutually exclusive. + if ((loopOp.isAuto() && (loopOp.isIndependent() || loopOp.isSeq())) || + (loopOp.isIndependent() && loopOp.isSeq())) { + return loopOp.emitError("only one of " + acc::LoopOp::getAutoAttrName() + + ", " + acc::LoopOp::getIndependentAttrName() + + ", " + acc::LoopOp::getSeqAttrName() + + " can be present at the same time."); + } + + // Gang, worker and vector are incompatible with seq + if (loopOp.isSeq() && + loopOp.getExecutionMapping() != OpenACCExecMapping::NONE) { + loopOp.emitError("gang, worker or vector cannot appear with the seq attr."); + } + + // Check non-empty body () + if (llvm::hasSingleElement(loopOp.region()) && + llvm::hasSingleElement(loopOp.region().front().getOperations())) + loopOp.emitError("expected non-empty body."); + + return success(); +} + #define GET_OP_CLASSES #include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc" diff --git a/mlir/test/Dialect/OpenACC/invalid.mlir b/mlir/test/Dialect/OpenACC/invalid.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/Dialect/OpenACC/invalid.mlir @@ -0,0 +1,72 @@ +// RUN: mlir-opt -split-input-file -verify-diagnostics %s + +func @loop_seq() { + %lb = constant 0 : index + %ub = constant 10 : index + %st = constant 1 : index + // expected-error@+1 {{gang, worker or vector cannot appear with the seq attr.}} + acc.loop gang { + scf.for %x = %lb to %ub step %st { + } + acc.yield + } attributes {seq} + // expected-error@+1 {{gang, worker or vector cannot appear with the seq attr.}} + acc.loop worker { + scf.for %x = %lb to %ub step %st { + } + acc.yield + } attributes {seq} + // expected-error@+1 {{gang, worker or vector cannot appear with the seq attr.}} + acc.loop vector { + scf.for %x = %lb to %ub step %st { + } + acc.yield + } attributes {seq} + // expected-error@+1 {{gang, worker or vector cannot appear with the seq attr.}} + acc.loop gang worker { + scf.for %x = %lb to %ub step %st { + } + acc.yield + } attributes {seq} + // expected-error@+1 {{gang, worker or vector cannot appear with the seq attr.}} + acc.loop gang vector { + scf.for %x = %lb to %ub step %st { + } + acc.yield + } attributes {seq} + // expected-error@+1 {{gang, worker or vector cannot appear with the seq attr.}} + acc.loop worker vector { + scf.for %x = %lb to %ub step %st { + } + acc.yield + } attributes {seq} + // expected-error@+1 {{gang, worker or vector cannot appear with the seq attr.}} + acc.loop gang worker vector { + scf.for %x = %lb to %ub step %st { + } + acc.yield + } attributes {seq} + return +} + +// --- + +func @loop_empty_body() { + // expected-error@+1 {{expected non-empty body.}} + acc.loop { + acc.yield + } + return +} + +// --- + +func @loop_exclusive_attr() { + // expected-error@+1 {{only one of auto, independent, seq can be present at the same time.}} + acc.loop { + acc.yield + } attributes {auto, seq} + return +} + +// --- diff --git a/mlir/test/Dialect/OpenACC/ops.mlir b/mlir/test/Dialect/OpenACC/ops.mlir --- a/mlir/test/Dialect/OpenACC/ops.mlir +++ b/mlir/test/Dialect/OpenACC/ops.mlir @@ -186,27 +186,54 @@ // CHECK-NEXT: return %{{.*}} : memref<10xf32> // CHECK-NEXT: } -func @testop() -> () { +func @testop(%a: memref<10xf32>) -> () { + %lb = constant 0 : index + %ub = constant 10 : index + %st = constant 1 : index %workerNum = constant 1 : i64 %vectorLength = constant 128 : i64 %gangNum = constant 8 : i64 %gangStatic = constant 2 : i64 %tileSize = constant 2 : i64 acc.loop gang worker vector { + scf.for %x = %lb to %ub step %st { + } + acc.yield } acc.loop gang(num: %gangNum) { + scf.for %x = %lb to %ub step %st { + } + acc.yield } acc.loop gang(static: %gangStatic) { + scf.for %x = %lb to %ub step %st { + } + acc.yield } acc.loop worker(%workerNum) { + scf.for %x = %lb to %ub step %st { + } + acc.yield } acc.loop vector(%vectorLength) { + scf.for %x = %lb to %ub step %st { + } + acc.yield } acc.loop gang(num: %gangNum) worker vector { + scf.for %x = %lb to %ub step %st { + } + acc.yield } acc.loop gang(num: %gangNum, static: %gangStatic) worker(%workerNum) vector(%vectorLength) { + scf.for %x = %lb to %ub step %st { + } + acc.yield } acc.loop tile(%tileSize : i64, %tileSize : i64) { + scf.for %x = %lb to %ub step %st { + } + acc.yield } return } @@ -217,18 +244,42 @@ // CHECK-NEXT: [[GANGSTATIC:%.*]] = constant 2 : i64 // CHECK-NEXT: [[TILESIZE:%.*]] = constant 2 : i64 // CHECK-NEXT: acc.loop gang worker vector { +// CHECK-NEXT: scf.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} { +// CHECK-NEXT: } +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop gang(num: [[GANGNUM]]) { +// CHECK-NEXT: scf.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} { +// CHECK-NEXT: } +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop gang(static: [[GANGSTATIC]]) { +// CHECK-NEXT: scf.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} { +// CHECK-NEXT: } +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop worker([[WORKERNUM]]) { +// CHECK-NEXT: scf.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} { +// CHECK-NEXT: } +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop vector([[VECTORLENGTH]]) { +// CHECK-NEXT: scf.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} { +// CHECK-NEXT: } +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop gang(num: [[GANGNUM]]) worker vector { +// CHECK-NEXT: scf.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} { +// CHECK-NEXT: } +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop gang(num: [[GANGNUM]], static: [[GANGSTATIC]]) worker([[WORKERNUM]]) vector([[VECTORLENGTH]]) { +// CHECK-NEXT: scf.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} { +// CHECK-NEXT: } +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop tile([[TILESIZE]]: i64, [[TILESIZE]]: i64) { +// CHECK-NEXT: scf.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} { +// CHECK-NEXT: } +// CHECK-NEXT: acc.yield // CHECK-NEXT: }