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

Reply via email to