llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clangir Author: Konstantinos Parasyris (koparasy) <details> <summary>Changes</summary> Emit norecurse, mustprogress, and sycl-module-id. This matches the classic behavior that is specific to the SYCL kernel caller. --- Full diff: https://github.com/llvm/llvm-project/pull/224667.diff 6 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIRDialect.td (+3) - (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+16) - (modified) clang/lib/CIR/CodeGen/CIRGenModule.h (+2) - (modified) clang/lib/CIR/CodeGen/CIRGenSYCL.cpp (+23-3) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+21-6) - (added) clang/test/CIR/CodeGenSYCL/kernel-caller-attributes.cpp (+39) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td index e323eff0b9aa6..f07cd7c0dbeb3 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td @@ -53,6 +53,9 @@ def CIR_Dialect : Dialect { static llvm::StringRef getStrictFPAttrName() { return "strictfp"; } static llvm::StringRef getNoDuplicatesAttrName() { return "noduplicate"; } static llvm::StringRef getConvergentAttrName() { return "convergent"; } + static llvm::StringRef getNoRecurseAttrName() { return "norecurse"; } + static llvm::StringRef getMustProgressAttrName() { return "mustprogress"; } + static llvm::StringRef getSYCLModuleIdAttrName() { return "sycl-module-id"; } static llvm::StringRef getNoUnwindAttrName() { return "nounwind"; } static llvm::StringRef getModuleLevelAsmAttrName() { return "cir.module_asm"; } static llvm::StringRef getGlobalCtorsAttrName() { return "cir.global_ctors"; } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 86a8736980773..1ef61e3276bb6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -571,6 +571,22 @@ class CIRGenFunction : public CIRGenTypeCache { const clang::LangOptions &getLangOpts() const { return cgm.getLangOpts(); } + bool checkIfFunctionMustProgress() { + if (cgm.getCodeGenOpts().getFiniteLoops() == + clang::CodeGenOptions::FiniteLoopsKind::Never) + return false; + + // C++11 and later guarantees that a thread eventually will do one of the + // following (C++11 [intro.multithread]p24 and C++17 [intro.progress]p1): + // - terminate, + // - make a call to a library I/O function, + // - perform an access through a volatile glvalue, or + // - perform a synchronization operation or an atomic operation. + // + // Hence each function is 'mustprogress' in C++11 or later. + return getLangOpts().CPlusPlus11; + } + /// True if an insertion point is defined. If not, this indicates that the /// current code being emitted is unreachable. /// FIXME(cir): we need to inspect this and perhaps use a cleaner mechanism diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 51b9c420c94be..4bdd302764b44 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -668,6 +668,8 @@ class CIRGenModule : public CIRGenTypeCache { /// function declared with the sycl_kernel_entry_point attribute. void emitSYCLKernelCaller(const clang::FunctionDecl *kernelEntryPointFn, clang::ASTContext &ctx); + + void addSYCLModuleIdAttr(cir::FuncOp fn); void emitGlobalVarDefinition(const clang::VarDecl *vd, bool isTentative = false); diff --git a/clang/lib/CIR/CodeGen/CIRGenSYCL.cpp b/clang/lib/CIR/CodeGen/CIRGenSYCL.cpp index edba083c7c406..cfbd580fa3aff 100644 --- a/clang/lib/CIR/CodeGen/CIRGenSYCL.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenSYCL.cpp @@ -74,6 +74,24 @@ void CIRGenFunction::emitSYCLKernelCaller( eraseEmptyAndUnusedBlocks(funcOp); } +static void setSYCLKernelAttributes(CIRGenFunction &cgf, cir::FuncOp fn) { + mlir::MLIRContext *ctx = &cgf.getMLIRContext(); + // SYCL 2020 device language restrictions require forward progress and + // disallow recursion. + fn->setAttr(cir::CIRDialect::getNoRecurseAttrName(), + mlir::UnitAttr::get(ctx)); + if (cgf.checkIfFunctionMustProgress()) + fn->setAttr(cir::CIRDialect::getMustProgressAttrName(), + mlir::UnitAttr::get(ctx)); +} + +void CIRGenModule::addSYCLModuleIdAttr(cir::FuncOp fn) { + assert(getLangOpts().SYCLIsDevice); + StringRef moduleId = theModule.getSymName().value_or(""); + fn->setAttr(cir::CIRDialect::getSYCLModuleIdAttrName(), + mlir::StringAttr::get(&getMLIRContext(), moduleId)); +} + void CIRGenModule::emitSYCLKernelCaller(const FunctionDecl *kernelEntryPointFn, ASTContext &ctx) { assert(ctx.getLangOpts().SYCLIsDevice && @@ -119,18 +137,20 @@ void CIRGenModule::emitSYCLKernelCaller(const FunctionDecl *kernelEntryPointFn, // opFuncCallingConv onto the FuncOp, so set it from the target hook. funcOp.setCallingConv(getTargetCIRGenInfo().getDeviceKernelCallingConv()); + CIRGenFunction cgf(*this, builder); + // Route through the shared attribute path so generic function attributes // (e.g. convergent) are applied, matching classic CodeGen's // SetLLVMFunctionAttributes. There is no FunctionDecl, so pass an empty // GlobalDecl. setCIRFunctionAttributes(GlobalDecl(), fnInfo, funcOp, /*isThunk=*/false); - // TODO: attributes applied by classic CodeGen not yet handled in CIR: - // SetSYCLKernelAttributes (norecurse, mustprogress), addSYCLModuleIdAttr. + setSYCLKernelAttributes(cgf, funcOp); + addSYCLModuleIdAttr(funcOp); + assert(!cir::MissingFeatures::setLLVMFunctionFEnvAttributes()); // Emit the SYCL kernel caller function. - CIRGenFunction cgf(*this, builder); llvm::SaveAndRestore<CIRGenFunction *> savedCGF(curCGF, &cgf); { mlir::OpBuilder::InsertionGuard guard(builder); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 186d91599e806..e1e309947786e 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2672,6 +2672,9 @@ static bool shouldDropFuncAttribute(cir::FuncOp func, mlir::NamedAttribute attr, attr.getName() == func.getSideEffectAttrName() || attr.getName() == CIRDialect::getNoReturnAttrName() || attr.getName() == CIRDialect::getStrictFPAttrName() || + attr.getName() == CIRDialect::getNoRecurseAttrName() || + attr.getName() == CIRDialect::getMustProgressAttrName() || + attr.getName() == CIRDialect::getSYCLModuleIdAttrName() || attr.getName() == func.getAnnotationsAttrName(); } @@ -2811,13 +2814,25 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite( if (op->hasAttr(CIRDialect::getNoReturnAttrName())) fn.setNoreturn(true); - // The LLVM dialect's LLVMFuncOp has no dedicated field for the `strictfp` - // function attribute, so route it through the `passthrough` array. The MLIR - // LLVM IR translator forwards `passthrough` entries to LLVM IR as function + // Function attributes with no dedicated field on the LLVM dialect's + // LLVMFuncOp are routed through the `passthrough` array. The MLIR LLVM IR + // translator forwards `passthrough` entries to LLVM IR as function // attributes. - if (op->hasAttr(CIRDialect::getStrictFPAttrName())) - fn.setPassthroughAttr(rewriter.getArrayAttr( - {rewriter.getStringAttr(CIRDialect::getStrictFPAttrName())})); + SmallVector<mlir::Attribute> passthrough; + for (llvm::StringRef flagAttr : + {CIRDialect::getStrictFPAttrName(), CIRDialect::getNoRecurseAttrName(), + CIRDialect::getMustProgressAttrName()}) + if (op->hasAttr(flagAttr)) + passthrough.push_back(rewriter.getStringAttr(flagAttr)); + + if (auto moduleId = op->getAttrOfType<mlir::StringAttr>( + CIRDialect::getSYCLModuleIdAttrName())) + passthrough.push_back(rewriter.getArrayAttr( + {rewriter.getStringAttr(CIRDialect::getSYCLModuleIdAttrName()), + moduleId})); + + if (!passthrough.empty()) + fn.setPassthroughAttr(rewriter.getArrayAttr(passthrough)); if (std::optional<cir::InlineKind> inlineKind = op.getInlineKind()) { fn.setNoInline(*inlineKind == cir::InlineKind::NoInline); diff --git a/clang/test/CIR/CodeGenSYCL/kernel-caller-attributes.cpp b/clang/test/CIR/CodeGenSYCL/kernel-caller-attributes.cpp new file mode 100644 index 0000000000000..ba0e563a4acff --- /dev/null +++ b/clang/test/CIR/CodeGenSYCL/kernel-caller-attributes.cpp @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spirv64-unknown-unknown -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spirv64-unknown-unknown -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spirv64-unknown-unknown -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +// The SYCL kernel caller offload entry point receives the SYCL 2020 device +// language attributes: it must not recurse (norecurse) and is guaranteed to +// make forward progress in C++11 and later (mustprogress). It also carries the +// "sycl-module-id" attribute, marking it as an entry point for +// per-translation-unit device-code splitting. This matches classic CodeGen's +// SetSYCLKernelAttributes and addSYCLModuleIdAttr. + +template <typename KernelName, typename... Ts> +void sycl_kernel_launch(const char *, Ts...) {} + +template <typename KernelName, typename KernelType> +[[clang::sycl_kernel_entry_point(KernelName)]] +void kernel_single_task(KernelType kf) { kf(); } + +struct KN; + +void test(int *p) { + kernel_single_task<KN>([p]() { *p = 42; }); +} + +// CIR-LABEL: cir.func +// CIR-SAME: @_ZTS2KN +// CIR-SAME: cc(spir_kernel) +// CIR-SAME: mustprogress +// CIR-SAME: norecurse +// CIR-SAME: "sycl-module-id" = "{{.*}}kernel-caller-attributes.cpp" + +// LLVM: define spir_kernel void @_ZTS2KN({{.*}}) #[[KATTR:[0-9]+]] +// LLVM: attributes #[[KATTR]] = {{[{].*}}mustprogress{{.*}}norecurse{{.*}}"sycl-module-id"="{{.*}}kernel-caller-attributes.cpp" + +// OGCG: define spir_kernel void @_ZTS2KN({{.*}}) #[[KATTR:[0-9]+]] +// OGCG: attributes #[[KATTR]] = {{[{].*}}mustprogress{{.*}}norecurse{{.*}}"sycl-module-id"="{{.*}}kernel-caller-attributes.cpp" `````````` </details> https://github.com/llvm/llvm-project/pull/224667 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
