diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -965,6 +965,59 @@ `map` `(` custom($map_operands, type($map_operands), $map_types) `)` attr-dict }]; + + let hasVerifier = 1; +} + +//===----------------------------------------------------------------------===// +// 2.12.7 declare target directive +//===----------------------------------------------------------------------===// + +def ClauseDeviceTypeAny : I32EnumAttrCase<"any", 0>; +def ClauseDeviceTypeHost : I32EnumAttrCase<"host", 1>; +def ClauseDeviceTypeNoHost : I32EnumAttrCase<"nohost", 2>; + +def ClauseDeviceType : I32EnumAttr< + "ClauseDeviceType", + "device_type clause", + [ClauseDeviceTypeAny, ClauseDeviceTypeHost, ClauseDeviceTypeNoHost]> { + let genSpecializedAttr = 0; + let cppNamespace = "::mlir::omp"; +} +def ClauseDeviceTypeAttr : EnumAttr { + let assemblyFormat = "`(` $value `)`"; +} + +def TargetDeclareOp : OpenMP_Op<"target.declare"> { + let summary = "declare target directive"; + let description = [{ + The declare target directive specifies that variables, functions (C, C++ and Fortran), + and subroutines (Fortran) are mapped to a device. The declare target directive is a + declarative directive. + + The $device_type argument contains an integer from 0 to 2, which specifies + one of the three options that can be given to the device_type clause (e.g. + host | nohost | any). + + The $to_operands argument contains symbol references for functions and + global variables captured by the "to" clause of declare target or explicitly + captured via brackets e.g: declare target(var1, var2), the device type is + implicitly expected to be any. + + The $link_operands argument contains symbol references for functions and global + variables captured by the "link" clause of declare target e.g: declare target + link(var1, var2). The device type is explicitly specified by the link clause. + }]; + + let arguments = (ins ClauseDeviceTypeAttr:$device_type, + OptionalAttr:$to_operands, + OptionalAttr:$link_operands); + + let assemblyFormat = [{ + oilist( `to` `(` $to_operands `)` + | `link` `(` $link_operands `)` + ) `device_type` `` $device_type attr-dict + }]; let hasVerifier = 1; } diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp --- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp +++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp @@ -1346,6 +1346,24 @@ return success(); } +//===----------------------------------------------------------------------===// +// Verifier for TargetDeclareOp +//===----------------------------------------------------------------------===// + +LogicalResult TargetDeclareOp::verify() { + auto toOps = getToOperands(); + auto linkOps = getLinkOperands(); + + // The operation should have at least one item in either operand list (there + // should be at least one implicit capture), otherwise the op is essentially a + // no-op + if ((!toOps || toOps->empty()) && (!linkOps || linkOps->empty())) + return emitOpError() + << "the TargetDeclareOp must have ToOperands or LinkOperands"; + + return success(); +} + #define GET_ATTRDEF_CLASSES #include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc" diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir --- a/mlir/test/Dialect/OpenMP/invalid.mlir +++ b/mlir/test/Dialect/OpenMP/invalid.mlir @@ -1551,3 +1551,59 @@ } llvm.mlir.global internal @_QFsubEx() : i32 + +// ----- + +func.func @omp_target_declare() -> () { + // expected-error @below {{op the TargetDeclareOp must have ToOperands or LinkOperands}} + omp.target.declare to([]) link([]) device_type(any) + return +} + +// ----- + +func.func @omp_target_declare() -> () { + // expected-error @below {{op the TargetDeclareOp must have ToOperands or LinkOperands}} + omp.target.declare to() link() device_type(any) + return +} + +// ----- + +func.func @omp_target_declare() -> () { + // expected-error @below {{op the TargetDeclareOp must have ToOperands or LinkOperands}} + omp.target.declare to() device_type(any) + return +} + +// ----- + +func.func @omp_target_declare() -> () { + // expected-error @below {{op the TargetDeclareOp must have ToOperands or LinkOperands}} + omp.target.declare link() device_type(any) + return +} + +// ----- + +func.func @omp_target_declare() -> () { + // expected-error @below {{op the TargetDeclareOp must have ToOperands or LinkOperands}} + omp.target.declare to([]) device_type(any) + return +} + +// ----- + +func.func @omp_target_declare() -> () { + // expected-error @below {{op the TargetDeclareOp must have ToOperands or LinkOperands}} + omp.target.declare link([]) device_type(any) + return +} + +// ----- + +func.func @omp_target_declare() -> () { + // expected-error @below {{op the TargetDeclareOp must have ToOperands or LinkOperands}} + omp.target.declare device_type(any) + return +} diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir --- a/mlir/test/Dialect/OpenMP/ops.mlir +++ b/mlir/test/Dialect/OpenMP/ops.mlir @@ -1860,3 +1860,53 @@ // CHECK: return return } + +// ----- + +llvm.mlir.global internal @test_global_symbol() : i32 + +func.func @test_func_symbol() -> () { + return +} + +// CHECK-LABEL: omp_target_declare +func.func @omp_target_declare() -> () { + // CHECK: omp.target.declare to([@omp_target_declare, @test_func_symbol, @test_global_symbol]) link([@test_func_symbol, @omp_target_declare, @test_global_symbol]) device_type(host) + omp.target.declare to([@omp_target_declare, @test_func_symbol, @test_global_symbol]) link([@test_func_symbol, @omp_target_declare, @test_global_symbol]) device_type(host) + // CHECK: omp.target.declare to([@omp_target_declare, @test_func_symbol, @test_global_symbol]) link([@test_func_symbol, @omp_target_declare, @test_global_symbol]) device_type(any) + omp.target.declare to([@omp_target_declare, @test_func_symbol, @test_global_symbol]) link([@test_func_symbol, @omp_target_declare, @test_global_symbol]) device_type(any) + // CHECK: omp.target.declare to([@omp_target_declare, @test_func_symbol, @test_global_symbol]) link([@test_func_symbol, @omp_target_declare, @test_global_symbol]) device_type(nohost) + omp.target.declare to([@omp_target_declare, @test_func_symbol, @test_global_symbol]) link([@test_func_symbol, @omp_target_declare, @test_global_symbol]) device_type(nohost) + // CHECK: omp.target.declare to([@omp_target_declare, @test_func_symbol]) link([@test_func_symbol, @omp_target_declare]) device_type(host) + omp.target.declare to([@omp_target_declare, @test_func_symbol]) link([@test_func_symbol, @omp_target_declare]) device_type(host) + // CHECK: omp.target.declare to([@omp_target_declare, @test_func_symbol]) link([@test_func_symbol, @omp_target_declare]) device_type(any) + omp.target.declare to([@omp_target_declare, @test_func_symbol]) link([@test_func_symbol, @omp_target_declare]) device_type(any) + // CHECK: omp.target.declare to([@omp_target_declare, @test_func_symbol]) link([@test_func_symbol, @omp_target_declare]) device_type(nohost) + omp.target.declare to([@omp_target_declare, @test_func_symbol]) link([@test_func_symbol, @omp_target_declare]) device_type(nohost) + // CHECK: omp.target.declare to([@omp_target_declare, @test_func_symbol]) device_type(host) + omp.target.declare to([@omp_target_declare, @test_func_symbol]) device_type(host) + // CHECK: omp.target.declare to([@omp_target_declare, @test_func_symbol]) device_type(any) + omp.target.declare to([@omp_target_declare, @test_func_symbol]) device_type(any) + // CHECK: omp.target.declare to([@omp_target_declare, @test_func_symbol]) device_type(nohost) + omp.target.declare to([@omp_target_declare, @test_func_symbol]) device_type(nohost) + // CHECK: omp.target.declare link([@omp_target_declare, @test_func_symbol]) device_type(host) + omp.target.declare link([@omp_target_declare, @test_func_symbol]) device_type(host) + // CHECK: omp.target.declare link([@omp_target_declare, @test_func_symbol]) device_type(any) + omp.target.declare link([@omp_target_declare, @test_func_symbol]) device_type(any) + // CHECK: omp.target.declare link([@omp_target_declare, @test_func_symbol]) device_type(nohost) + omp.target.declare link([@omp_target_declare, @test_func_symbol]) device_type(nohost) + // CHECK: omp.target.declare to([@omp_target_declare]) device_type(host) + omp.target.declare to([@omp_target_declare]) device_type(host) + // CHECK: omp.target.declare to([@omp_target_declare]) device_type(any) + omp.target.declare to([@omp_target_declare]) device_type(any) + // CHECK: omp.target.declare to([@omp_target_declare]) device_type(nohost) + omp.target.declare to([@omp_target_declare]) device_type(nohost) + // CHECK: omp.target.declare link([@omp_target_declare]) device_type(host) + omp.target.declare link([@omp_target_declare]) device_type(host) + // CHECK: omp.target.declare link([@omp_target_declare]) device_type(any) + omp.target.declare link([@omp_target_declare]) device_type(any) + // CHECK: omp.target.declare link([@omp_target_declare]) device_type(nohost) + omp.target.declare link([@omp_target_declare]) device_type(nohost) + + return +}