[clang] 64a6af1 - [CIR][OpenCL] Add OpenCL language version module attributes (#219687)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 11 20:28:02 PDT 2026
Author: Akimasa Watanuki
Date: 2026-09-12T12:27:55+09:00
New Revision: 64a6af1666c9bbb63eb86c0697a3709a4cca8e50
URL: https://github.com/llvm/llvm-project/commit/64a6af1666c9bbb63eb86c0697a3709a4cca8e50
DIFF: https://github.com/llvm/llvm-project/commit/64a6af1666c9bbb63eb86c0697a3709a4cca8e50.diff
LOG: [CIR][OpenCL] Add OpenCL language version module attributes (#219687)
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
Added:
clang/test/CIR/IR/invalid-version.cir
clang/test/CIR/IR/version.cir
Modified:
clang/include/clang/CIR/Dialect/IR/CIRDialect.td
clang/include/clang/CIR/Dialect/IR/CIROpenCLAttrs.td
clang/lib/CIR/Dialect/IR/CIRDialect.cpp
clang/lib/CIR/Dialect/IR/CIROpenCLAttrs.cpp
clang/test/CIR/Transforms/cxx-abi-lowering-attrs.cir
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index 7c5c2d20bbaf4..e323eff0b9aa6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -27,6 +27,8 @@ def CIR_Dialect : Dialect {
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
@@ -99,6 +101,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..65712c1fdaeba 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROpenCLAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROpenCLAttrs.td
@@ -43,4 +43,38 @@ 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.
+
+ The `cir.cl.cxx.version` module attribute requires a companion
+ `cir.cl.version` attribute specifying the compatible OpenCL version.
+
+ 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>,
+ cir.cl.version = #cir.cl.version<3, 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 d7b1551b2e7ed..23426bed89f6a 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -111,6 +111,85 @@ 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 (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();
+}
+
+static LogicalResult verifyOpenCLVersionAttr(Operation *op,
+ NamedAttribute attr) {
+ if (failed(verifyOpenCLVersionAttrPlacement(op, attr)))
+ return failure();
+
+ StringRef attrName = attr.getName().getValue();
+ auto version = dyn_cast<cir::OpenCLVersionAttr>(attr.getValue());
+ if (!version) {
+ return op->emitError() << "expected " << attrName
+ << " to be #cir.cl.version";
+ }
+
+ if (attrName == CIRDialect::getOpenCLCXXVersionAttrName())
+ return verifyOpenCLCXXVersion(cast<ModuleOp>(op), version);
+
+ return success();
+}
+
+LogicalResult cir::CIRDialect::verifyRegionArgAttribute(
+ Operation *op, unsigned /*regionIndex*/, unsigned /*argIndex*/,
+ NamedAttribute attr) {
+ if (!isOpenCLVersionAttrName(attr.getName().getValue()))
+ return success();
+
+ return verifyOpenCLVersionAttrPlacement(op, attr);
+}
+
+LogicalResult cir::CIRDialect::verifyRegionResultAttribute(
+ Operation *op, unsigned /*regionIndex*/, unsigned /*resultIndex*/,
+ NamedAttribute attr) {
+ if (!isOpenCLVersionAttrName(attr.getName().getValue()))
+ return success();
+
+ return verifyOpenCLVersionAttrPlacement(op, attr);
+}
+
//===----------------------------------------------------------------------===//
// Dialect attribute verification
//===----------------------------------------------------------------------===//
@@ -172,7 +251,11 @@ static LogicalResult verifyOffloadContainer(mlir::Operation *op) {
LogicalResult
cir::CIRDialect::verifyOperationAttribute(mlir::Operation *op,
mlir::NamedAttribute attr) {
- if (attr.getName() == getOffloadContainerAttrName()) {
+ llvm::StringRef attrName = attr.getName().getValue();
+ if (isOpenCLVersionAttrName(attrName))
+ return verifyOpenCLVersionAttr(op, attr);
+
+ if (attrName == getOffloadContainerAttrName()) {
if (!mlir::isa<mlir::UnitAttr>(attr.getValue()))
return op->emitOpError() << "expects '" << getOffloadContainerAttrName()
<< "' to be a unit attribute";
@@ -182,8 +265,7 @@ cir::CIRDialect::verifyOperationAttribute(mlir::Operation *op,
// The container verifier owns the structural contract between a container
// and the modules it holds. All this can add is that the kind attribute
// never lands on something that is not a module.
- if (attr.getName() == getOffloadKindAttrName() &&
- !mlir::isa<mlir::ModuleOp>(op))
+ if (attrName == getOffloadKindAttrName() && !mlir::isa<mlir::ModuleOp>(op))
return op->emitOpError() << "expects '" << getOffloadKindAttrName()
<< "' attribute to be attached to '"
<< mlir::ModuleOp::getOperationName() << "'";
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