diff --git a/clang/include/clang/CIR/Dialect/IR/CIROpenCLAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIROpenCLAttrs.td index 294f18c9414d..1a47186de581 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROpenCLAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROpenCLAttrs.td @@ -147,4 +147,25 @@ def OpenCLKernelArgMetadataAttr let genVerifyDecl = 1; } +//===----------------------------------------------------------------------===// +// OpenCLVersionAttr +//===----------------------------------------------------------------------===// + +def OpenCLVersionAttr : CIR_Attr<"OpenCLVersion", "cl.version"> { + let summary = "OpenCL version"; + let parameters = (ins "int32_t":$major, "int32_t":$minor); + let description = [{ + Represents the version of OpenCL. + + Example: + ``` + // Module compiled from OpenCL 1.2. + module attributes {cir.cl.version = cir.cl.version<1, 2>} {} + // Module compiled from OpenCL 3.0. + module attributes {cir.cl.version = cir.cl.version<3, 0>} {} + ``` + }]; + let assemblyFormat = "`<` $major `,` $minor `>`"; +} + #endif // MLIR_CIR_DIALECT_CIR_OPENCL_ATTRS diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index fece8f9fa723..2d857dcfe3c8 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2768,6 +2768,16 @@ void CIRGenModule::Release() { // TODO: buildModuleLinkOptions } + // Emit OpenCL specific module metadata: OpenCL/SPIR version. + if (langOpts.CUDAIsDevice && getTriple().isSPIRV()) + llvm_unreachable("CUDA SPIR-V NYI"); + if (langOpts.OpenCL) { + buildOpenCLMetadata(); + // Emit SPIR version. + if (getTriple().isSPIR()) + llvm_unreachable("SPIR target NYI"); + } + // TODO: FINISH THE REST OF THIS } @@ -3235,3 +3245,17 @@ void CIRGenModule::genKernelArgMetadata(mlir::cir::FuncOp Fn, llvm_unreachable("NYI HIPSaveKernelArgName"); } } + +void CIRGenModule::buildOpenCLMetadata() { + // SPIR v2.0 s2.13 - The OpenCL version used by the module is stored in the + // opencl.ocl.version named metadata node. + // C++ for OpenCL has a distinct mapping for versions compatibile with OpenCL. + unsigned version = langOpts.getOpenCLCompatibleVersion(); + unsigned major = version / 100; + unsigned minor = (version % 100) / 10; + + auto clVersionAttr = + mlir::cir::OpenCLVersionAttr::get(builder.getContext(), major, minor); + + theModule->setAttr("cir.cl.version", clVersionAttr); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index fa6da9c9506d..895f6a54d403 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -702,6 +702,9 @@ class CIRGenModule : public CIRGenTypeCache { const FunctionDecl *FD = nullptr, CIRGenFunction *CGF = nullptr); + /// Emits OpenCL specific Metadata e.g. OpenCL version. + void buildOpenCLMetadata(); + private: // An ordered map of canonical GlobalDecls to their mangled names. llvm::MapVector MangledDeclNames; diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp index 08aeb902b78e..f8fbd3e0846f 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp @@ -41,6 +41,8 @@ class CIRDialectLLVMIRTranslationInterface mlir::LLVM::ModuleTranslation &moduleTranslation) const override { if (auto func = dyn_cast(op)) { amendFunction(func, instructions, attribute, moduleTranslation); + } else if (auto mod = dyn_cast(op)) { + amendModule(mod, attribute, moduleTranslation); } return mlir::success(); } @@ -60,6 +62,29 @@ class CIRDialectLLVMIRTranslationInterface } private: + // Translate CIR's module attributes to LLVM's module metadata + void amendModule(mlir::ModuleOp module, mlir::NamedAttribute attribute, + mlir::LLVM::ModuleTranslation &moduleTranslation) const { + llvm::Module *llvmModule = moduleTranslation.getLLVMModule(); + llvm::LLVMContext &llvmContext = llvmModule->getContext(); + + if (auto openclVersionAttr = mlir::dyn_cast( + attribute.getValue())) { + auto *int32Ty = llvm::IntegerType::get(llvmContext, 32); + llvm::Metadata *oclVerElts[] = { + llvm::ConstantAsMetadata::get( + llvm::ConstantInt::get(int32Ty, openclVersionAttr.getMajor())), + llvm::ConstantAsMetadata::get( + llvm::ConstantInt::get(int32Ty, openclVersionAttr.getMinor()))}; + llvm::NamedMDNode *oclVerMD = + llvmModule->getOrInsertNamedMetadata("opencl.ocl.version"); + oclVerMD->addOperand(llvm::MDNode::get(llvmContext, oclVerElts)); + } + + // Drop ammended CIR attribute from LLVM op. + module->removeAttr(attribute.getName()); + } + // Translate CIR's extra function attributes to LLVM's function attributes. void amendFunction(mlir::LLVM::LLVMFuncOp func, llvm::ArrayRef instructions, diff --git a/clang/test/CIR/CodeGen/OpenCL/opencl-version.cl b/clang/test/CIR/CodeGen/OpenCL/opencl-version.cl new file mode 100644 index 000000000000..f0536a560b97 --- /dev/null +++ b/clang/test/CIR/CodeGen/OpenCL/opencl-version.cl @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -cl-std=CL3.0 -O0 -fclangir -emit-cir -triple spirv64-unknown-unknown %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR-CL30 +// RUN: %clang_cc1 -cl-std=CL3.0 -O0 -fclangir -emit-llvm -triple spirv64-unknown-unknown %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM-CL30 +// RUN: %clang_cc1 -cl-std=CL1.2 -O0 -fclangir -emit-cir -triple spirv64-unknown-unknown %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR-CL12 +// RUN: %clang_cc1 -cl-std=CL1.2 -O0 -fclangir -emit-llvm -triple spirv64-unknown-unknown %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM-CL12 + +// CIR-CL30: module {{.*}} attributes {{{.*}}cir.cl.version = #cir.cl.version<3, 0> +// LLVM-CL30: !opencl.ocl.version = !{![[MDCL30:[0-9]+]]} +// LLVM-CL30: ![[MDCL30]] = !{i32 3, i32 0} + +// CIR-CL12: module {{.*}} attributes {{{.*}}cir.cl.version = #cir.cl.version<1, 2> +// LLVM-CL12: !opencl.ocl.version = !{![[MDCL12:[0-9]+]]} +// LLVM-CL12: ![[MDCL12]] = !{i32 1, i32 2}