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 @@ -200,7 +200,8 @@ //===----------------------------------------------------------------------===// def OpenACC_LoopOp : OpenACC_Op<"loop", - [AttrSizedOperandSegments]> { + [AttrSizedOperandSegments, + SingleBlockImplicitTerminator<"acc::YieldOp">]> { let summary = "loop construct"; let description = [{ @@ -228,13 +229,14 @@ Optional:$gangStatic, Optional:$workerNum, Optional:$vectorLength, - UnitAttr:$loopSeq, - UnitAttr:$loopIndependent, - UnitAttr:$loopAuto, + UnitAttr:$seq, + UnitAttr:$independent, + UnitAttr:$auto_, Variadic:$tileOperands, Variadic:$privateOperands, OptionalAttr:$reductionOp, - Variadic:$reductionOperands); + Variadic:$reductionOperands, + DefaultValuedAttr:$exec_mapping); let results = (outs Variadic:$results); @@ -256,7 +258,7 @@ static StringRef getReductionKeyword() { return "reduction"; } }]; - 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 @@ -487,7 +487,7 @@ /// region attr-dict? static ParseResult parseLoopOp(OpAsmParser &parser, OperationState &result) { Builder &builder = parser.getBuilder(); - unsigned executionMapping = 0; + unsigned executionMapping = OpenACCExecMapping::NONE; SmallVector operandTypes; SmallVector privateOperands, reductionOperands; SmallVector tileOperands; @@ -567,7 +567,7 @@ reductionOperands, operandTypes, result))) return failure(); - if (executionMapping != 0) + if (executionMapping != acc::OpenACCExecMapping::NONE) result.addAttribute(LoopOp::getExecutionMappingAttrName(), builder.getI64IntegerAttr(executionMapping)); @@ -597,13 +597,7 @@ static void print(OpAsmPrinter &printer, LoopOp &op) { printer << LoopOp::getOperationName(); - unsigned execMapping = - (op.getAttrOfType(LoopOp::getExecutionMappingAttrName()) != - nullptr) - ? op.getAttrOfType(LoopOp::getExecutionMappingAttrName()) - .getInt() - : 0; - + unsigned execMapping = op.exec_mapping(); if (execMapping & OpenACCExecMapping::GANG) { printer << " " << LoopOp::getGangKeyword(); Value gangNum = op.gangNum(); @@ -661,5 +655,31 @@ LoopOp::getOperandSegmentSizeAttr()}); } +static LogicalResult verifyLoopOp(acc::LoopOp loopOp) { + // auto, independent and seq attribute are mutually exclusive. + if ((loopOp.auto_() && (loopOp.independent() || loopOp.seq())) || + (loopOp.independent() && loopOp.seq())) { + loopOp.emitError("only one of " + acc::LoopOp::getAutoAttrName() + ", " + + acc::LoopOp::getIndependentAttrName() + ", " + + acc::LoopOp::getSeqAttrName() + + " can be present at the same time"); + return failure(); + } + + // Gang, worker and vector are incompatible with seq. + if (loopOp.seq() && loopOp.exec_mapping() != OpenACCExecMapping::NONE) { + loopOp.emitError("gang, worker or vector cannot appear with the seq attr"); + return failure(); + } + + // Check non-empty body(). + if (loopOp.region().empty()) { + loopOp.emitError("expected non-empty body."); + return failure(); + } + + 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,70 @@ +// RUN: mlir-opt -split-input-file -verify-diagnostics %s + +// expected-error@+1 {{gang, worker or vector cannot appear with the seq attr}} +acc.loop gang { + "some.op"() : () -> () + acc.yield +} attributes {seq} + +// ----- + +// expected-error@+1 {{gang, worker or vector cannot appear with the seq attr}} +acc.loop worker { + "some.op"() : () -> () + acc.yield +} attributes {seq} + +// ----- + +// expected-error@+1 {{gang, worker or vector cannot appear with the seq attr}} +acc.loop vector { + "some.op"() : () -> () + acc.yield +} attributes {seq} + +// ----- + +// expected-error@+1 {{gang, worker or vector cannot appear with the seq attr}} +acc.loop gang worker { + "some.op"() : () -> () + acc.yield +} attributes {seq} + +// ----- + +// expected-error@+1 {{gang, worker or vector cannot appear with the seq attr}} +acc.loop gang vector { + "some.op"() : () -> () + acc.yield +} attributes {seq} + +// ----- + +// expected-error@+1 {{gang, worker or vector cannot appear with the seq attr}} +acc.loop worker vector { + "some.op"() : () -> () + acc.yield +} attributes {seq} + +// ----- + +// expected-error@+1 {{gang, worker or vector cannot appear with the seq attr}} +acc.loop gang worker vector { + "some.op"() : () -> () + acc.yield +} attributes {seq} + +// ----- + +// expected-error@+1 {{expected non-empty body.}} +acc.loop { +} + +// ----- + +// expected-error@+1 {{only one of auto, independent, seq can be present at the same time}} +acc.loop { + acc.yield +} attributes {auto_, seq} + +// ----- 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 @@ -1,8 +1,8 @@ -// RUN: mlir-opt %s | FileCheck %s +// RUN: mlir-opt -allow-unregistered-dialect %s | FileCheck %s // Verify the printed output can be parsed. -// RUN: mlir-opt %s | mlir-opt | FileCheck %s +// RUN: mlir-opt -allow-unregistered-dialect %s | mlir-opt -allow-unregistered-dialect | FileCheck %s // Verify the generic form can be parsed. -// RUN: mlir-opt -mlir-print-op-generic %s | mlir-opt | FileCheck %s +// RUN: mlir-opt -allow-unregistered-dialect -mlir-print-op-generic %s | mlir-opt -allow-unregistered-dialect | FileCheck %s func @compute1(%A: memref<10x10xf32>, %B: memref<10x10xf32>, %C: memref<10x10xf32>) -> memref<10x10xf32> { %c0 = constant 0 : index @@ -186,27 +186,43 @@ // CHECK-NEXT: return %{{.*}} : memref<10xf32> // CHECK-NEXT: } -func @testop() -> () { +func @testop(%a: memref<10xf32>) -> () { %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 { + "some.op"() : () -> () + acc.yield } acc.loop gang(num: %gangNum) { + "some.op"() : () -> () + acc.yield } acc.loop gang(static: %gangStatic) { + "some.op"() : () -> () + acc.yield } acc.loop worker(%workerNum) { + "some.op"() : () -> () + acc.yield } acc.loop vector(%vectorLength) { + "some.op"() : () -> () + acc.yield } acc.loop gang(num: %gangNum) worker vector { + "some.op"() : () -> () + acc.yield } acc.loop gang(num: %gangNum, static: %gangStatic) worker(%workerNum) vector(%vectorLength) { + "some.op"() : () -> () + acc.yield } acc.loop tile(%tileSize : i64, %tileSize : i64) { + "some.op"() : () -> () + acc.yield } return } @@ -217,20 +233,36 @@ // CHECK-NEXT: [[GANGSTATIC:%.*]] = constant 2 : i64 // CHECK-NEXT: [[TILESIZE:%.*]] = constant 2 : i64 // CHECK-NEXT: acc.loop gang worker vector { +// CHECK-NEXT: "some.op"() : () -> () +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop gang(num: [[GANGNUM]]) { +// CHECK-NEXT: "some.op"() : () -> () +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop gang(static: [[GANGSTATIC]]) { +// CHECK-NEXT: "some.op"() : () -> () +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop worker([[WORKERNUM]]) { +// CHECK-NEXT: "some.op"() : () -> () +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop vector([[VECTORLENGTH]]) { +// CHECK-NEXT: "some.op"() : () -> () +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop gang(num: [[GANGNUM]]) worker vector { +// CHECK-NEXT: "some.op"() : () -> () +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop gang(num: [[GANGNUM]], static: [[GANGSTATIC]]) worker([[WORKERNUM]]) vector([[VECTORLENGTH]]) { +// CHECK-NEXT: "some.op"() : () -> () +// CHECK-NEXT: acc.yield // CHECK-NEXT: } // CHECK-NEXT: acc.loop tile([[TILESIZE]]: i64, [[TILESIZE]]: i64) { +// CHECK-NEXT: "some.op"() : () -> () +// CHECK-NEXT: acc.yield // CHECK-NEXT: }