[clang] [CIR][OpenCL] Add OpenCL language version module attributes (PR #219686)
Akimasa Watanuki via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 29 07:55:27 PDT 2026
https://github.com/Men-cotton created https://github.com/llvm/llvm-project/pull/219686
Add structured CIR module attributes for OpenCL and C++ for OpenCL language versions. Verify their module-level placement and version components so lowering can consume explicit source-language version state.
Assisted-by: Codex / GPT-5.6 Sol
>From ac9f57069f82b0e2442ee1ac462e50abb34dde48 Mon Sep 17 00:00:00 2001
From: mencotton <mencotton0410 at gmail.com>
Date: Mon, 8 Jun 2026 20:56:30 +0900
Subject: [PATCH] [CIR][OpenCL] Add OpenCL language version module attributes
Add structured CIR module attributes for OpenCL and C++ for OpenCL language versions. Verify their module-level placement and version components so lowering can consume explicit source-language version state.
Assisted-by: Codex / GPT-5.6 Sol
---
.../clang/CIR/Dialect/IR/CIRDialect.td | 5 ++
.../clang/CIR/Dialect/IR/CIROpenCLAttrs.td | 28 +++++++
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 76 +++++++++++++++++++
clang/lib/CIR/Dialect/IR/CIROpenCLAttrs.cpp | 15 ++++
clang/test/CIR/IR/invalid-version.cir | 73 ++++++++++++++++++
clang/test/CIR/IR/version.cir | 19 +++++
.../CIR/Transforms/cxx-abi-lowering-attrs.cir | 4 +-
7 files changed, 219 insertions(+), 1 deletion(-)
create mode 100644 clang/test/CIR/IR/invalid-version.cir
create mode 100644 clang/test/CIR/IR/version.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index 135cbdcc7d7be..eb116e030fec5 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -25,6 +25,9 @@ def CIR_Dialect : Dialect {
let cppNamespace = "::cir";
let useDefaultAttributePrinterParser = 1;
+ let hasOperationAttrVerify = 1;
+ let hasRegionArgAttrVerify = 1;
+ let hasRegionResultAttrVerify = 1;
// Enable constant materialization for the CIR dialect. This generates a
// declaration for the cir::CIRDialect::materializeConstant function. This
@@ -94,6 +97,8 @@ def CIR_Dialect : Dialect {
static llvm::StringRef getAMDGPUXnackAttrName() { return "cir.amdgpu_xnack"; }
static llvm::StringRef getAMDGPUSramEccAttrName() { return "cir.amdgpu_sramecc"; }
static llvm::StringRef getOpenCLKernelArgMetadataAttrName() { return "cir.cl.kernel_arg_metadata"; }
+ static llvm::StringRef getOpenCLVersionAttrName() { return "cir.cl.version"; }
+ static llvm::StringRef getOpenCLCXXVersionAttrName() { return "cir.cl.cxx.version"; }
static llvm::StringRef getDefaultTlsModelAttrName() { return "cir.default_tls_model"; }
void registerAttributes();
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROpenCLAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIROpenCLAttrs.td
index 94b41da4c925d..2a556108c4b9b 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROpenCLAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROpenCLAttrs.td
@@ -43,4 +43,32 @@ def CIR_OpenCLKernelArgMetadataAttr
let canHaveIllegalCXXABIType = 0;
}
+//===----------------------------------------------------------------------===//
+// OpenCLVersionAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_OpenCLVersionAttr : CIR_Attr<"OpenCLVersion", "cl.version"> {
+ let summary = "OpenCL version";
+ let description = [{
+ Represents an OpenCL language version preserved as module metadata.
+
+ Example:
+ ```
+ // Module compiled from OpenCL C 1.2.
+ module attributes {cir.cl.version = #cir.cl.version<1, 2>} {}
+ // Module compiled from C++ for OpenCL 2021.
+ module attributes {cir.cl.cxx.version = #cir.cl.version<2021, 0>} {}
+ ```
+ }];
+
+ let parameters = (ins
+ "int32_t":$major,
+ "int32_t":$minor
+ );
+
+ let assemblyFormat = "`<` $major `,` $minor `>`";
+ let genVerifyDecl = 1;
+ let canHaveIllegalCXXABIType = 0;
+}
+
#endif // CLANG_CIR_DIALECT_IR_CIROPENCLATTRS_TD
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 8f7bf8062e2e8..b47a424f716ca 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -110,6 +110,82 @@ Operation *cir::CIRDialect::materializeConstant(mlir::OpBuilder &builder,
mlir::cast<mlir::TypedAttr>(value));
}
+static bool isOpenCLVersionAttrName(StringRef attrName) {
+ return attrName == CIRDialect::getOpenCLVersionAttrName() ||
+ attrName == CIRDialect::getOpenCLCXXVersionAttrName();
+}
+
+static LogicalResult verifyOpenCLVersionAttrPlacement(Operation *op,
+ NamedAttribute attr) {
+ StringRef attrName = attr.getName().getValue();
+ if (!isOpenCLVersionAttrName(attrName) || isa<ModuleOp>(op))
+ return success();
+
+ return op->emitError() << attrName
+ << " attribute must be attached to a module";
+}
+
+static bool areOpenCLVersionsCompatible(cir::OpenCLVersionAttr openCLVersion,
+ cir::OpenCLVersionAttr cxxVersion) {
+ return (openCLVersion.getMajor() == 2 && openCLVersion.getMinor() == 0 &&
+ cxxVersion.getMajor() == 1 && cxxVersion.getMinor() == 0) ||
+ (openCLVersion.getMajor() == 3 && openCLVersion.getMinor() == 0 &&
+ cxxVersion.getMajor() == 2021 && cxxVersion.getMinor() == 0);
+}
+
+static LogicalResult verifyOpenCLCXXVersion(ModuleOp module,
+ cir::OpenCLVersionAttr cxxVersion) {
+ Attribute openCLAttr =
+ module->getAttr(CIRDialect::getOpenCLVersionAttrName());
+ if (!openCLAttr)
+ return module.emitError()
+ << "module attribute '" << CIRDialect::getOpenCLCXXVersionAttrName()
+ << "' requires the companion attribute '"
+ << CIRDialect::getOpenCLVersionAttrName() << "'";
+
+ auto openCLVersion = dyn_cast<cir::OpenCLVersionAttr>(openCLAttr);
+ if (!openCLVersion)
+ return success();
+
+ if (!areOpenCLVersionsCompatible(openCLVersion, cxxVersion))
+ return module.emitError("incompatible OpenCL and C++ for OpenCL versions");
+
+ return success();
+}
+
+LogicalResult cir::CIRDialect::verifyOperationAttribute(Operation *op,
+ NamedAttribute attr) {
+ StringRef attrName = attr.getName().getValue();
+ if (!isOpenCLVersionAttrName(attrName))
+ return success();
+
+ if (failed(verifyOpenCLVersionAttrPlacement(op, attr)))
+ return failure();
+
+ auto version = dyn_cast<cir::OpenCLVersionAttr>(attr.getValue());
+ if (!version) {
+ return op->emitError() << "expected " << attrName
+ << " to be #cir.cl.version";
+ }
+
+ if (attrName == getOpenCLCXXVersionAttrName())
+ return verifyOpenCLCXXVersion(cast<ModuleOp>(op), version);
+
+ return success();
+}
+
+LogicalResult cir::CIRDialect::verifyRegionArgAttribute(
+ Operation *op, unsigned /*regionIndex*/, unsigned /*argIndex*/,
+ NamedAttribute attr) {
+ return verifyOpenCLVersionAttrPlacement(op, attr);
+}
+
+LogicalResult cir::CIRDialect::verifyRegionResultAttribute(
+ Operation *op, unsigned /*regionIndex*/, unsigned /*resultIndex*/,
+ NamedAttribute attr) {
+ return verifyOpenCLVersionAttrPlacement(op, attr);
+}
+
//===----------------------------------------------------------------------===//
// Helpers
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIROpenCLAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIROpenCLAttrs.cpp
index fac083c3af7a7..ac7e764f01e0f 100644
--- a/clang/lib/CIR/Dialect/IR/CIROpenCLAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIROpenCLAttrs.cpp
@@ -36,3 +36,18 @@ LogicalResult OpenCLKernelArgMetadataAttr::verify(
return success();
}
+
+//===----------------------------------------------------------------------===//
+// OpenCLVersionAttr definitions
+//===----------------------------------------------------------------------===//
+
+LogicalResult
+OpenCLVersionAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+ int32_t major, int32_t minor) {
+ if (major <= 0)
+ return emitError() << "OpenCL major version must be positive";
+ if (minor < 0)
+ return emitError() << "OpenCL minor version must be non-negative";
+
+ return success();
+}
diff --git a/clang/test/CIR/IR/invalid-version.cir b/clang/test/CIR/IR/invalid-version.cir
new file mode 100644
index 0000000000000..f75c4c6365307
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-version.cir
@@ -0,0 +1,73 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+// expected-error @below {{OpenCL major version must be positive}}
+#attr = #cir.cl.version<-1, 2>
+
+// -----
+
+// expected-error @below {{OpenCL minor version must be non-negative}}
+#attr = #cir.cl.version<3, -1>
+
+// -----
+
+// expected-error @below {{OpenCL major version must be positive}}
+#attr = #cir.cl.version<0, 0>
+
+// -----
+
+// expected-error @below {{expected cir.cl.version to be #cir.cl.version}}
+module attributes {cir.cl.version = "bad"} {
+}
+
+// -----
+
+// expected-error @below {{expected cir.cl.cxx.version to be #cir.cl.version}}
+module attributes {cir.cl.cxx.version = "bad"} {
+}
+
+// -----
+
+// expected-error @below {{module attribute 'cir.cl.cxx.version' requires the companion attribute 'cir.cl.version'}}
+module attributes {cir.cl.cxx.version = #cir.cl.version<2021, 0>} {
+}
+
+// -----
+
+// expected-error @below {{incompatible OpenCL and C++ for OpenCL versions}}
+module attributes {
+ cir.cl.cxx.version = #cir.cl.version<2021, 0>,
+ cir.cl.version = #cir.cl.version<2, 0>
+} {
+}
+
+// -----
+
+module {
+ // expected-error @below {{cir.cl.version attribute must be attached to a module}}
+ cir.func @not_module_attr() attributes {cir.cl.version = #cir.cl.version<1, 2>} {
+ cir.return
+ }
+}
+
+// -----
+
+module {
+ // expected-error @below {{cir.cl.cxx.version attribute must be attached to a module}}
+ cir.func @not_module_attr() attributes {cir.cl.cxx.version = #cir.cl.version<2021, 0>} {
+ cir.return
+ }
+}
+
+// -----
+
+module {
+ // expected-error @below {{cir.cl.version attribute must be attached to a module}}
+ cir.func private @not_module_arg(!cir.int<s, 32> {cir.cl.version = #cir.cl.version<1, 2>})
+}
+
+// -----
+
+module {
+ // expected-error @below {{cir.cl.cxx.version attribute must be attached to a module}}
+ cir.func private @not_module_cxx_result() -> (!cir.int<s, 32> {cir.cl.cxx.version = #cir.cl.version<2021, 0>})
+}
diff --git a/clang/test/CIR/IR/version.cir b/clang/test/CIR/IR/version.cir
new file mode 100644
index 0000000000000..47603a8dff658
--- /dev/null
+++ b/clang/test/CIR/IR/version.cir
@@ -0,0 +1,19 @@
+// RUN: cir-opt %s -split-input-file --verify-roundtrip | FileCheck %s
+
+// CHECK: module attributes {cir.cl.version = #cir.cl.version<1, 2>}
+module attributes {cir.cl.version = #cir.cl.version<1, 2>} { }
+
+// -----
+
+// CHECK: module attributes {cir.cl.version = #cir.cl.version<3, 0>}
+module attributes {cir.cl.version = #cir.cl.version<3, 0>} { }
+
+// -----
+
+// CHECK: module attributes {cir.cl.cxx.version = #cir.cl.version<1, 0>, cir.cl.version = #cir.cl.version<2, 0>}
+module attributes {cir.cl.cxx.version = #cir.cl.version<1, 0>, cir.cl.version = #cir.cl.version<2, 0>} { }
+
+// -----
+
+// CHECK: module attributes {cir.cl.cxx.version = #cir.cl.version<2021, 0>, cir.cl.version = #cir.cl.version<3, 0>}
+module attributes {cir.cl.cxx.version = #cir.cl.version<2021, 0>, cir.cl.version = #cir.cl.version<3, 0>} { }
diff --git a/clang/test/CIR/Transforms/cxx-abi-lowering-attrs.cir b/clang/test/CIR/Transforms/cxx-abi-lowering-attrs.cir
index 569b1f6a87ab1..06259eda595a1 100644
--- a/clang/test/CIR/Transforms/cxx-abi-lowering-attrs.cir
+++ b/clang/test/CIR/Transforms/cxx-abi-lowering-attrs.cir
@@ -44,7 +44,9 @@ module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
// Attrs don't really allow getting a 'bad' type into them. We attempt to
// transform them anyway, but they'll probably never fail the legalizer.
- cir.trap
+ // OpenCLVersionAttr contains no types and remains unchanged.
+ cir.trap {test.opencl_versions = [#cir.cl.version<3, 0>]}
+ // CHECK: cir.trap {test.opencl_versions = [#cir.cl.version<3, 0>]}
}
// cir::TypeAttr: function type is a type attr, so this shows it converting.
More information about the cfe-commits
mailing list