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 @@ -1322,6 +1322,73 @@ let hasVerifier = 0; } +//===----------------------------------------------------------------------===// +// 2.15.1 Routine Directive +//===----------------------------------------------------------------------===// + +def OpenACC_RoutineOp : OpenACC_Op<"routine", [IsolatedFromAbove]> { + let summary = "acc routine operation"; + + let description = [{ + The `acc.routine` operation is used to capture the clauses of acc + routine directive, including the associated function name. The associated + function keeps track of its corresponding routine declaration through + the `RoutineInfoAttr`. + + Example: + + ```mlir + func.func @acc_func(%a : i64) -> () attributes {acc.routine_info = #acc.routine_info<[@acc_func_rout1]>} { + return + } + acc.routine @acc_func_rout1 func(@acc_func) gang + ``` + }]; + + let arguments = (ins SymbolNameAttr:$sym_name, + SymbolNameAttr:$func_name, + OptionalAttr:$bind_name, + OptionalAttr:$gang, + OptionalAttr:$worker, + OptionalAttr:$vector, + OptionalAttr:$seq, + OptionalAttr:$nohost, + OptionalAttr:$implicit, + OptionalAttr:$gangDim); + + let extraClassDeclaration = [{ + static StringRef getGangDimKeyword() { return "dim"; } + }]; + + let assemblyFormat = [{ + $sym_name `func` `(` $func_name `)` + oilist ( + `bind` `(` $bind_name `)` + | `gang` `` custom($gang, $gangDim) + | `worker` $worker + | `vector` $vector + | `seq` $seq + | `nohost` $nohost + | `implicit` $implicit + ) attr-dict-with-keyword + }]; + + let hasVerifier = 1; +} + +def RoutineInfoAttr : OpenACC_Attr<"RoutineInfo", "routine_info"> { + let summary = "Keeps track of associated acc routine information"; + + let description = [{ + This attribute is used to create the association between a function and + its `acc.routine` operation. A `func.func` uses this if its name + was referenced in an `acc routine` directive. + }]; + + let parameters = (ins ArrayRefParameter<"SymbolRefAttr", "">:$accRoutines); + let assemblyFormat = "`<` `[` `` $accRoutines `]` `>`"; +} + //===----------------------------------------------------------------------===// // 2.14.1. Init Directive //===----------------------------------------------------------------------===// 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 @@ -1037,6 +1037,61 @@ return checkDeclareOperands(*this, this->getDataClauseOperands()); } +//===----------------------------------------------------------------------===// +// RoutineOp +//===----------------------------------------------------------------------===// + +LogicalResult acc::RoutineOp::verify() { + int parallelism = 0; + parallelism += getGang() ? 1 : 0; + parallelism += getWorker() ? 1 : 0; + parallelism += getVector() ? 1 : 0; + parallelism += getSeq() ? 1 : 0; + + if (parallelism > 1) + return emitError() << "only one of `gang`, `worker`, `vector`, `seq` can " + "be present at the same time"; + + return success(); +} + +static ParseResult parseRoutineGangClause(OpAsmParser &parser, UnitAttr &gang, + IntegerAttr &gangDim) { + // Since gang clause exists, ensure that unit attribute is set. + gang = UnitAttr::get(parser.getBuilder().getContext()); + + // Next, look for dim on gang. Don't initialize `gangDim` yet since + // we leave it without attribute if there is no `dim` specifier. + if (succeeded(parser.parseOptionalLParen())) { + // Look for syntax that looks like `dim = 1 : i32`. + // Thus first look for `dim =` + if (failed(parser.parseKeyword(RoutineOp::getGangDimKeyword())) || + failed(parser.parseEqual())) + return failure(); + + int64_t dimValue; + Type valueType; + // Now look for `1 : i32` + if (failed(parser.parseInteger(dimValue)) || + failed(parser.parseColonType(valueType))) + return failure(); + + gangDim = IntegerAttr::get(valueType, dimValue); + + if (failed(parser.parseRParen())) + return failure(); + } + + return success(); +} + +void printRoutineGangClause(OpAsmPrinter &p, Operation *op, UnitAttr gang, + IntegerAttr gangDim) { + if (gangDim) + p << "(" << RoutineOp::getGangDimKeyword() << " = " << gangDim.getValue() + << " : " << gangDim.getType() << ")"; +} + //===----------------------------------------------------------------------===// // InitOp //===----------------------------------------------------------------------===// 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 @@ -1634,3 +1634,33 @@ // CHECK-NEXT: %[[DELETE:.*]] = acc.getdeviceptr varPtr(%[[ADDR]] : !llvm.ptr) -> !llvm.ptr {dataClause = #acc} // CHECK-NEXT: acc.declare_exit dataOperands(%[[DELETE]] : !llvm.ptr) // CHECK-NEXT: acc.delete accPtr(%[[DELETE]] : !llvm.ptr) + +// ----- + +func.func @acc_func(%a : i64) -> () attributes {acc.routine_info = #acc.routine_info<[@acc_func_rout1,@acc_func_rout2,@acc_func_rout3, + @acc_func_rout4,@acc_func_rout5,@acc_func_rout6,@acc_func_rout7,@acc_func_rout8,@acc_func_rout9]>} { + return +} + +acc.routine @acc_func_rout1 func(@acc_func) +acc.routine @acc_func_rout2 func(@acc_func) bind("acc_func_gpu") +acc.routine @acc_func_rout3 func(@acc_func) bind("acc_func_gpu_gang") gang +acc.routine @acc_func_rout4 func(@acc_func) bind("acc_func_gpu_vector") vector +acc.routine @acc_func_rout5 func(@acc_func) bind("acc_func_gpu_worker") worker +acc.routine @acc_func_rout6 func(@acc_func) bind("acc_func_gpu_seq") seq +acc.routine @acc_func_rout7 func(@acc_func) bind("acc_func_gpu_imp_gang") implicit gang +acc.routine @acc_func_rout8 func(@acc_func) bind("acc_func_gpu_vector_nohost") vector nohost +acc.routine @acc_func_rout9 func(@acc_func) bind("acc_func_gpu_gang_dim1") gang(dim = 1 : i32) + +// CHECK-LABEL: func.func @acc_func( +// CHECK: attributes {acc.routine_info = #acc.routine_info<[@acc_func_rout1, @acc_func_rout2, @acc_func_rout3, +// CHECK: @acc_func_rout4, @acc_func_rout5, @acc_func_rout6, @acc_func_rout7, @acc_func_rout8, @acc_func_rout9]>} +// CHECK: acc.routine @acc_func_rout1 func(@acc_func) +// CHECK: acc.routine @acc_func_rout2 func(@acc_func) bind("acc_func_gpu") +// CHECK: acc.routine @acc_func_rout3 func(@acc_func) bind("acc_func_gpu_gang") gang +// CHECK: acc.routine @acc_func_rout4 func(@acc_func) bind("acc_func_gpu_vector") vector +// CHECK: acc.routine @acc_func_rout5 func(@acc_func) bind("acc_func_gpu_worker") worker +// CHECK: acc.routine @acc_func_rout6 func(@acc_func) bind("acc_func_gpu_seq") seq +// CHECK: acc.routine @acc_func_rout7 func(@acc_func) bind("acc_func_gpu_imp_gang") gang implicit +// CHECK: acc.routine @acc_func_rout8 func(@acc_func) bind("acc_func_gpu_vector_nohost") vector nohost +// CHECK: acc.routine @acc_func_rout9 func(@acc_func) bind("acc_func_gpu_gang_dim1") gang(dim = 1 : i32)