[Mlir-commits] [mlir] [MLIR][OpenMP] Add verification for DeclareTargetInterface (PR #217294)

Sergio Afonso llvmlistbot at llvm.org
Mon Aug 24 04:19:01 PDT 2026


https://github.com/skatrak updated https://github.com/llvm/llvm-project/pull/217294

>From 3f93b1609779138f5d14f21d32137dd5160414e8 Mon Sep 17 00:00:00 2001
From: Sergio Afonso <Sergio.AfonsoFumero at amd.com>
Date: Mon, 17 Aug 2026 14:29:19 +0100
Subject: [PATCH] [MLIR][OpenMP] Add verification for DeclareTargetInterface

This patch introduces checks to ensure the "omp.declare_target"
attribute is only attached to `DeclareTargetInterface` operations, it is
always the right type attribute and its properties do not conflict with
the operation they are attached to.
---
 .../mlir/Dialect/OpenMP/OpenMPDialect.td      |  1 +
 mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp  | 42 +++++++++++++++++++
 mlir/test/Dialect/OpenMP/attr.mlir            | 18 --------
 .../Dialect/OpenMP/invalid-interface.mlir     | 28 +++++++++++++
 4 files changed, 71 insertions(+), 18 deletions(-)

diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPDialect.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPDialect.td
index 8ef8fcccf2d57..dbc851a5e297c 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPDialect.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPDialect.td
@@ -18,6 +18,7 @@ def OpenMP_Dialect : Dialect {
   let useDefaultAttributePrinterParser = 1;
   let useStrictPropertiesInAssemblyFormat = 1;
   let useDefaultTypePrinterParser = 1;
+  let hasOperationAttrVerify = 1;
 }
 
 #endif  // OPENMP_DIALECT
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index c957321771ab7..f06c665c7013b 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -343,6 +343,48 @@ void OpenMPDialect::initialize() {
       mlir::omp::DeclareTargetDefaultModel<mlir::func::FuncOp>>(*getContext());
 }
 
+//===----------------------------------------------------------------------===//
+// Dialect operation attribute verification
+//===----------------------------------------------------------------------===//
+
+static LogicalResult verifyDeclareTargetAttr(Operation *op, Attribute attr) {
+  if (!isa<DeclareTargetInterface>(op))
+    return op->emitError() << "omp.declare_target can only be applied to "
+                              "DeclareTargetInterface ops";
+
+  auto declareTargetAttr = dyn_cast<DeclareTargetAttr>(attr);
+  if (!declareTargetAttr)
+    return op->emitError()
+           << "omp.declare_target must be an #omp.declaretarget attribute";
+
+  if (isa<mlir::FunctionOpInterface>(op)) {
+    if (declareTargetAttr.getAutomap())
+      return op->emitOpError()
+             << "omp.declare_target 'automap' is not valid on functions";
+
+    // TODO: Disallow the `local` clause (OpenMP 6.0).
+    if (declareTargetAttr.getCaptureClause().getValue() ==
+        mlir::omp::DeclareTargetCaptureClause::link)
+      return op->emitOpError()
+             << "omp.declare_target 'link' is not valid on functions";
+  } else {
+    // TODO: Disallow the `indirect` clause (OpenMP 5.1).
+    if (declareTargetAttr.getImplicit())
+      return op->emitOpError()
+             << "omp.declare_target 'implicit' is only valid on functions";
+  }
+  return success();
+}
+
+LogicalResult
+OpenMPDialect::verifyOperationAttribute(Operation *op,
+                                        NamedAttribute attribute) {
+  if (attribute.getName() == "omp.declare_target")
+    return verifyDeclareTargetAttr(op, attribute.getValue());
+
+  return success();
+}
+
 //===----------------------------------------------------------------------===//
 // Parser and printer for Allocate Clause
 //===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/OpenMP/attr.mlir b/mlir/test/Dialect/OpenMP/attr.mlir
index 61a4e0df2f1ff..8c6f25f3bcaab 100644
--- a/mlir/test/Dialect/OpenMP/attr.mlir
+++ b/mlir/test/Dialect/OpenMP/attr.mlir
@@ -71,12 +71,6 @@ func.func @omp_decl_tar_host_to() -> () attributes {omp.declare_target = #omp.de
   return
 }
 
-// CHECK-LABEL: func @omp_decl_tar_host_link
-// CHECK-SAME: {{.*}} attributes {omp.declare_target = #omp.declaretarget<device_type = (host), capture_clause = (link)>} {
-func.func @omp_decl_tar_host_link() -> () attributes {omp.declare_target = #omp.declaretarget<device_type = (host), capture_clause = (link)>} {
-  return
-}
-
 // CHECK-LABEL: func @omp_decl_tar_host_enter
 // CHECK-SAME: {{.*}} attributes {omp.declare_target = #omp.declaretarget<device_type = (host), capture_clause = (enter)>} {
 func.func @omp_decl_tar_host_enter() -> () attributes {omp.declare_target = #omp.declaretarget<device_type = (host), capture_clause = (enter)>} {
@@ -89,12 +83,6 @@ func.func @omp_decl_tar_nohost_to() -> () attributes {omp.declare_target = #omp.
   return
 }
 
-// CHECK-LABEL: func @omp_decl_tar_nohost_link
-// CHECK-SAME: {{.*}} attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (link)>} {
-func.func @omp_decl_tar_nohost_link() -> () attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (link)>} {
-  return
-}
-
 // CHECK-LABEL: func @omp_decl_tar_nohost_enter
 // CHECK-SAME: {{.*}} attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (enter)>} {
 func.func @omp_decl_tar_nohost_enter() -> () attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (enter)>} {
@@ -107,12 +95,6 @@ func.func @omp_decl_tar_any_to() -> () attributes {omp.declare_target = #omp.dec
   return
 }
 
-// CHECK-LABEL: func @omp_decl_tar_any_link
-// CHECK-SAME: {{.*}} attributes {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (link)>} {
-func.func @omp_decl_tar_any_link() -> () attributes {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (link)>} {
-  return
-}
-
 // CHECK-LABEL: func @omp_decl_tar_any_enter
 // CHECK-SAME: {{.*}} attributes {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (enter)>} {
 func.func @omp_decl_tar_any_enter() -> () attributes {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (enter)>} {
diff --git a/mlir/test/Dialect/OpenMP/invalid-interface.mlir b/mlir/test/Dialect/OpenMP/invalid-interface.mlir
index 6fe64b0839e66..787b6a7ec00ce 100644
--- a/mlir/test/Dialect/OpenMP/invalid-interface.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid-interface.mlir
@@ -104,3 +104,31 @@ func.func @composable_conditional_combined(%x : i32) {
   } {omp.combined}
   return
 }
+
+// -----
+
+// expected-error @below {{omp.declare_target can only be applied to DeclareTargetInterface ops}}
+%0 = arith.constant { omp.declare_target = #omp.declaretarget<capture_clause = (enter)> } 2 : i32
+
+// -----
+
+// expected-error @below {{omp.declare_target must be an #omp.declaretarget attribute}}
+func.func private @declare_target_attr_type() attributes { omp.declare_target = 10 : i32 }
+
+// -----
+
+// expected-error @below {{omp.declare_target 'automap' is not valid on functions}}
+func.func private @declare_target_automap() attributes { omp.declare_target = #omp.declaretarget<automap = true>}
+
+// -----
+
+// expected-error @below {{omp.declare_target 'link' is not valid on functions}}
+func.func private @declare_target_link() attributes { omp.declare_target = #omp.declaretarget<capture_clause = (link)>}
+
+// -----
+
+// expected-error @below {{omp.declare_target 'implicit' is only valid on functions}}
+llvm.mlir.global @declare_target_implicit() {omp.declare_target = #omp.declaretarget<implicit = true>} : i32 {
+  %0 = llvm.mlir.constant(1 : i32) : i32
+  llvm.return %0 : i32
+}



More information about the Mlir-commits mailing list