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..d5fcfb06f8cd6 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -110,6 +110,94 @@ Operation *cir::CIRDialect::materializeConstant(mlir::OpBuilder &builder, mlir::cast(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(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(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(attr.getValue()); + if (!version) { + return op->emitError() << "expected " << attrName + << " to be #cir.cl.version"; + } + + if (attrName == CIRDialect::getOpenCLCXXVersionAttrName()) + return verifyOpenCLCXXVersion(cast(op), version); + + return success(); +} + +LogicalResult cir::CIRDialect::verifyOperationAttribute(Operation *op, + NamedAttribute attr) { + StringRef attrName = attr.getName().getValue(); + if (!isOpenCLVersionAttrName(attrName)) + return success(); + + return verifyOpenCLVersionAttr(op, attr); +} + +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); +} + //===----------------------------------------------------------------------===// // 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 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 {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 {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.