Author: Konstantinos Parasyris
Date: 2026-08-15T18:15:24-07:00
New Revision: 59d202c7711dabafafed4e408a50f46399322479

URL: 
https://github.com/llvm/llvm-project/commit/59d202c7711dabafafed4e408a50f46399322479
DIFF: 
https://github.com/llvm/llvm-project/commit/59d202c7711dabafafed4e408a50f46399322479.diff

LOG: [CIR][SYCL] Device kernel caller (#213771)

During device compilation, emit a SYCL kernel caller offload entry point
in
place of each function declared with the sycl_kernel_entry_point
attribute,
mirroring classic CodeGen's `CodeGenModule::EmitSYCLKernelCaller`.

Depends on #213728

Added: 
    

Modified: 
    clang/lib/CIR/CodeGen/CIRGenFunction.cpp
    clang/lib/CIR/CodeGen/CIRGenFunction.h
    clang/lib/CIR/CodeGen/CIRGenModule.cpp
    clang/lib/CIR/CodeGen/CIRGenModule.h
    clang/lib/CIR/CodeGen/CIRGenSYCL.cpp
    clang/lib/CIR/CodeGen/CIRGenTypes.cpp
    clang/lib/CIR/CodeGen/CIRGenTypes.h
    clang/lib/CIR/CodeGen/TargetInfo.h
    clang/lib/CIR/CodeGen/Targets/SPIRV.cpp
    clang/test/CIR/CodeGenSYCL/kernel-caller-entry-point.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 66e7b6d5061df..39cf3ee20d52b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -369,14 +369,17 @@ void CIRGenFunction::LexicalScope::emitImplicitReturn() {
   CIRGenBuilderTy &builder = cgf.getBuilder();
   LexicalScope *localScope = cgf.curLexScope;
 
-  const auto *fd = cast<clang::FunctionDecl>(cgf.curGD.getDecl());
+  // Synthesized functions (e.g. SYCL kernel caller entry points) have no
+  // FunctionDecl; the non-void flow-off-the-end handling below is guarded on
+  // fd.
+  const auto *fd = dyn_cast_or_null<clang::FunctionDecl>(cgf.curGD.getDecl());
 
   // In C++, flowing off the end of a non-void function is always undefined
   // behavior. In C, flowing off the end of a non-void function is undefined
   // behavior only if the non-existent return value is used by the caller.
   // That influences whether the terminating op is trap, unreachable, or
   // return.
-  if (cgf.getLangOpts().CPlusPlus && !fd->hasImplicitReturnZero() &&
+  if (fd && cgf.getLangOpts().CPlusPlus && !fd->hasImplicitReturnZero() &&
       !cgf.sawAsmBlock && !fd->getReturnType()->isVoidType() &&
       builder.getInsertionBlock() &&
       !previousOpIsNonYieldingCleanup(builder.getInsertionBlock())) {
@@ -651,7 +654,7 @@ mlir::LogicalResult CIRGenFunction::emitFunctionBody(const 
clang::Stmt *body) {
   return emitStmt(body, /*useCurrentScope=*/true);
 }
 
-static void eraseEmptyAndUnusedBlocks(cir::FuncOp func) {
+void CIRGenFunction::eraseEmptyAndUnusedBlocks(cir::FuncOp func) {
   // Remove any leftover blocks that are unreachable and empty, since they do
   // not represent unreachable code useful for warnings nor anything deemed
   // useful in general.

diff  --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 0117945993ade..20e2d13c9652f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -49,6 +49,7 @@ class LoopOp;
 } // namespace mlir
 
 namespace clang {
+class OutlinedFunctionDecl;
 class SYCLKernelCallStmt;
 } // namespace clang
 
@@ -2306,6 +2307,13 @@ class CIRGenFunction : public CIRGenTypeCache {
 
   mlir::LogicalResult emitSYCLKernelCallStmt(const SYCLKernelCallStmt &s);
 
+  void emitSYCLKernelCaller(const clang::OutlinedFunctionDecl *outlinedFnDecl,
+                            cir::FuncOp funcOp, cir::FuncType funcType,
+                            FunctionArgList &args);
+
+  /// Remove leftover empty and unreachable blocks from an emitted function.
+  static void eraseEmptyAndUnusedBlocks(cir::FuncOp func);
+
   std::optional<mlir::Value>
   emitTargetBuiltinExpr(unsigned builtinID, const clang::CallExpr *e,
                         ReturnValueSlot &returnValue);

diff  --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index e4650b775bc3c..16254d1bdba91 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -451,9 +451,13 @@ void CIRGenModule::emitDeferred() {
           fd->isDefined()) {
         // Functions with an invalid sycl_kernel_entry_point attribute are
         // ignored during device compilation.
-        if (!fd->getAttr<SYCLKernelEntryPointAttr>()->isInvalidAttr())
-          errorNYI(fd->getSourceRange(),
-                   "SYCL kernel caller offload entry point");
+        if (!fd->getAttr<SYCLKernelEntryPointAttr>()->isInvalidAttr()) {
+          // Generate and emit the SYCL kernel caller function.
+          emitSYCLKernelCaller(fd, getASTContext());
+          // Recurse to emit any symbols directly or indirectly referenced
+          // by the SYCL kernel caller function.
+          emitDeferred();
+        }
         // Do not emit the sycl_kernel_entry_point attributed function.
         continue;
       }

diff  --git a/clang/lib/CIR/CodeGen/CIRGenModule.h 
b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 9d19a58a05b4d..78612dd2e9de8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -654,6 +654,11 @@ class CIRGenModule : public CIRGenTypeCache {
   void emitGlobalDefinition(clang::GlobalDecl gd,
                             mlir::Operation *op = nullptr);
   void emitGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op);
+
+  /// Emit the SYCL kernel caller offload entry point function generated for a
+  /// function declared with the sycl_kernel_entry_point attribute.
+  void emitSYCLKernelCaller(const clang::FunctionDecl *kernelEntryPointFn,
+                            clang::ASTContext &ctx);
   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 9308b1fe4189f..b873c2d6f24b7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenSYCL.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenSYCL.cpp
@@ -11,9 +11,16 @@
 
//===----------------------------------------------------------------------===//
 
 #include "CIRGenFunction.h"
+#include "CIRGenModule.h"
 
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/SYCLKernelInfo.h"
 #include "clang/AST/StmtSYCL.h"
 
+#include "llvm/Support/SaveAndRestore.h"
+
 using namespace clang;
 using namespace clang::CIRGen;
 
@@ -33,3 +40,109 @@ CIRGenFunction::emitSYCLKernelCallStmt(const 
SYCLKernelCallStmt &s) {
   // of the original function body.
   return emitStmt(s.getKernelLaunchStmt(), /*useCurrentScope=*/true);
 }
+
+// Emit the body of a SYCL kernel caller offload entry point. Mirrors the tail
+// of generateCode, but is driven by an OutlinedFunctionDecl and an explicit
+// argument list rather than a FunctionDecl.
+void CIRGenFunction::emitSYCLKernelCaller(
+    const OutlinedFunctionDecl *outlinedFnDecl, cir::FuncOp funcOp,
+    cir::FuncType funcType, FunctionArgList &args) {
+  const Stmt *body = outlinedFnDecl->getBody();
+  SourceLocation loc = outlinedFnDecl->getLocation();
+  SourceRange bodyRange = body->getSourceRange();
+
+  // Synthesized entry point: no FunctionDecl, emitted with an empty 
GlobalDecl.
+  curGD = GlobalDecl();
+
+  SourceLocRAIIObject fnLoc{*this, loc.isValid() ? getLoc(loc)
+                                                 : builder.getUnknownLoc()};
+
+  mlir::Location fusedLoc = getLoc(bodyRange);
+  mlir::Block *entryBB = funcOp.addEntryBlock();
+
+  SymTableScopeTy varScope(symbolTable);
+  {
+    LexicalScope lexScope(*this, fusedLoc, entryBB);
+    startFunction(GlobalDecl(), getContext().VoidTy, funcOp, funcType, args,
+                  loc, bodyRange.getBegin());
+    if (mlir::failed(emitFunctionBody(body)))
+      return;
+    if (mlir::failed(funcOp.verifyBody()))
+      return;
+    finishFunction(body->getEndLoc());
+  }
+
+  eraseEmptyAndUnusedBlocks(funcOp);
+}
+
+void CIRGenModule::emitSYCLKernelCaller(const FunctionDecl *kernelEntryPointFn,
+                                        ASTContext &ctx) {
+  assert(ctx.getLangOpts().SYCLIsDevice &&
+         "SYCL kernel caller offload entry point functions can only be emitted"
+         " during device compilation");
+
+  const auto *kernelEntryPointAttr =
+      kernelEntryPointFn->getAttr<SYCLKernelEntryPointAttr>();
+  assert(kernelEntryPointAttr && "Missing sycl_kernel_entry_point attribute");
+  assert(!kernelEntryPointAttr->isInvalidAttr() &&
+         "sycl_kernel_entry_point attribute is invalid");
+
+  // Find the SYCLKernelCallStmt.
+  SYCLKernelCallStmt *kernelCallStmt =
+      cast<SYCLKernelCallStmt>(kernelEntryPointFn->getBody());
+
+  // Retrieve the SYCL kernel caller parameters from the OutlinedFunctionDecl.
+  FunctionArgList args;
+  const OutlinedFunctionDecl *outlinedFnDecl =
+      kernelCallStmt->getOutlinedFunctionDecl();
+  args.append(outlinedFnDecl->param_begin(), outlinedFnDecl->param_end());
+
+  // Compute the function info and CIR function type.
+  const CIRGenFunctionInfo &fnInfo =
+      getTypes().arrangeDeviceKernelCallerDeclaration(ctx.VoidTy, args);
+  cir::FuncType funcType = getTypes().getFunctionType(fnInfo);
+
+  // Retrieve the generated name for the SYCL kernel caller function.
+  CanQualType kernelNameType =
+      ctx.getCanonicalType(kernelEntryPointAttr->getKernelName());
+  const SYCLKernelInfo &kernelInfo = ctx.getSYCLKernelInfo(kernelNameType);
+
+  // Synthesized from the OutlinedFunctionDecl, not a FunctionDecl, so create
+  // the function directly with a null FunctionDecl (mirrors classic CodeGen's
+  // llvm::Function::Create).
+  cir::FuncOp funcOp = createCIRFunction(
+      getLoc(kernelEntryPointFn->getSourceRange()), kernelInfo.GetKernelName(),
+      funcType, /*funcDecl=*/nullptr);
+  funcOp.setLinkage(cir::GlobalLinkageKind::ExternalLinkage);
+
+  // Emit as a device kernel (e.g. spir_kernel). Classic CodeGen derives this
+  // from CC_DeviceKernel via SetLLVMFunctionAttributes; CIR does not yet route
+  // opFuncCallingConv onto the FuncOp, so set it from the target hook.
+  funcOp.setCallingConv(getTargetCIRGenInfo().getDeviceKernelCallingConv());
+
+  // 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.
+  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);
+    cgf.emitSYCLKernelCaller(outlinedFnDecl, funcOp, funcType, args);
+  }
+
+  setDSOLocal(static_cast<mlir::Operation *>(funcOp));
+
+  setNonAliasAttributes(GlobalDecl(), funcOp);
+  // CIR's setter takes a FunctionDecl; nullptr skips OutlinedFunctionDecl-
+  // derived attributes (e.g. inline hints), not yet handled.
+  assert(!cir::MissingFeatures::opFuncExtraAttrs());
+  setCIRFunctionAttributesForDefinition(/*fd=*/nullptr, funcOp);
+}

diff  --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp 
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index b2824d6f64700..346542134470a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -1,6 +1,7 @@
 #include "CIRGenTypes.h"
 
 #include "CIRGenCXXABI.h"
+#include "CIRGenCall.h"
 #include "CIRGenFunctionInfo.h"
 #include "CIRGenModule.h"
 #include "mlir/IR/BuiltinTypes.h"
@@ -785,6 +786,20 @@ const CIRGenFunctionInfo 
&CIRGenTypes::arrangeCIRFunctionInfo(
   return *fi;
 }
 
+const CIRGenFunctionInfo &
+CIRGenTypes::arrangeDeviceKernelCallerDeclaration(QualType resultType,
+                                                  const FunctionArgList &args) 
{
+  SmallVector<CanQualType, 16> argTypes;
+  for (const VarDecl *arg : args)
+    argTypes.push_back(astContext.getCanonicalParamType(arg->getType()));
+
+  // Classic CodeGen passes FnInfoOpts::None here; that is the no-op case, so
+  // nothing is needed even once CIR models FnInfoOpts.
+  return arrangeCIRFunctionInfo(
+      resultType->getCanonicalTypeUnqualified(), /*isInstanceMethod=*/false,
+      argTypes, FunctionType::ExtInfo(CC_DeviceKernel), RequiredArgs::All);
+}
+
 const CIRGenFunctionInfo &CIRGenTypes::arrangeGlobalDeclaration(GlobalDecl gd) 
{
   assert(!dyn_cast<ObjCMethodDecl>(gd.getDecl()) &&
          "This is reported as a FIXME in LLVM codegen");

diff  --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h 
b/clang/lib/CIR/CodeGen/CIRGenTypes.h
index a7827f76bd5f2..c5f8b521ed888 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h
@@ -44,6 +44,7 @@ class CallArgList;
 class CIRGenBuilderTy;
 class CIRGenCXXABI;
 class CIRGenModule;
+class FunctionArgList;
 
 /// This class organizes the cross-module state that is used while lowering
 /// AST types to CIR types.
@@ -186,6 +187,12 @@ class CIRGenTypes {
   const CIRGenFunctionInfo &
   arrangeFunctionDeclaration(const clang::FunctionDecl *fd);
 
+  /// Arrange the function info for a device kernel caller entry point (e.g. a
+  /// SYCL kernel caller).
+  const CIRGenFunctionInfo &
+  arrangeDeviceKernelCallerDeclaration(clang::QualType resultType,
+                                       const FunctionArgList &args);
+
   /// A builtin function is a freestanding function using the default
   /// C conventions.
   const CIRGenFunctionInfo &arrangeBuiltinFunctionCall(QualType resultType,

diff  --git a/clang/lib/CIR/CodeGen/TargetInfo.h 
b/clang/lib/CIR/CodeGen/TargetInfo.h
index 84680f82f4e4b..290027dad074f 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -153,6 +153,12 @@ class TargetCIRGenInfo {
                                    mlir::Operation *global,
                                    CIRGenModule &module) const {}
 
+  /// Get the CIR calling convention to use for a device kernel entry point
+  /// (e.g. an OpenCL/SYCL or CUDA/HIP kernel) on this target.
+  virtual cir::CallingConv getDeviceKernelCallingConv() const {
+    return cir::CallingConv::C;
+  }
+
   virtual bool isScalarizableAsmOperand(CIRGenFunction &cgf,
                                         mlir::Type ty) const {
     return false;

diff  --git a/clang/lib/CIR/CodeGen/Targets/SPIRV.cpp 
b/clang/lib/CIR/CodeGen/Targets/SPIRV.cpp
index 643c635128d09..f2d9810b36061 100644
--- a/clang/lib/CIR/CodeGen/Targets/SPIRV.cpp
+++ b/clang/lib/CIR/CodeGen/Targets/SPIRV.cpp
@@ -48,6 +48,10 @@ class SPIRVTargetCIRGenInfo : public TargetCIRGenInfo {
       func.setCallingConv(cir::CallingConv::SpirKernel);
     }
   }
+
+  cir::CallingConv getDeviceKernelCallingConv() const override {
+    return cir::CallingConv::SpirKernel;
+  }
 };
 
 } // namespace

diff  --git a/clang/test/CIR/CodeGenSYCL/kernel-caller-entry-point.cpp 
b/clang/test/CIR/CodeGenSYCL/kernel-caller-entry-point.cpp
index c6522064f2fdc..4d7ffe01fdebe 100644
--- a/clang/test/CIR/CodeGenSYCL/kernel-caller-entry-point.cpp
+++ b/clang/test/CIR/CodeGenSYCL/kernel-caller-entry-point.cpp
@@ -1,10 +1,25 @@
-// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spir64-unknown-unknown \
-// RUN:   -fclangir -emit-cir -verify %s
+// 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-prefixes=LLVM,LLVM-OGCG
+// 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-prefixes=OGCG,LLVM-OGCG
 
-// During device compilation, a SYCL kernel caller offload entry point is
-// emitted in place of each sycl_kernel_entry_point attributed function. That
-// lowering is not yet implemented in CIR, so it must be reported as a clean
-// "Not Yet Implemented" diagnostic rather than crashing.
+// On an ELF target such as spir64, the kernel caller entry point definition is
+// dso_local. dso_local is only attached to a definition, so this also verifies
+// that setDSOLocal() runs after body emission.
+// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spir64-unknown-unknown 
-fclangir -emit-cir %s -o %t-elf.cir
+// RUN: FileCheck --input-file=%t-elf.cir %s -check-prefix=CIR-ELF
+// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spir64-unknown-unknown 
-fclangir -emit-llvm %s -o %t-elf-cir.ll
+// RUN: FileCheck --input-file=%t-elf-cir.ll %s -check-prefix=LLVM-OGCG-ELF
+// RUN: %clang_cc1 -std=c++20 -fsycl-is-device -triple spir64-unknown-unknown 
-emit-llvm %s -o %t-elf.ll
+// RUN: FileCheck --input-file=%t-elf.ll %s -check-prefix=LLVM-OGCG-ELF
+
+// During device compilation, an offload kernel caller entry point is emitted
+// in place of each sycl_kernel_entry_point attributed function. The entry
+// point is named after the kernel name type and its body is the transformed
+// body held by the OutlinedFunctionDecl (which invokes the kernel functor).
+// The sycl_kernel_entry_point attributed function itself is not emitted.
 
 // Required by sycl_kernel_entry_point semantics.
 template <typename KernelName, typename... Ts>
@@ -12,12 +27,52 @@ void sycl_kernel_launch(const char *, Ts...) {}
 
 template <typename KernelName, typename KernelType>
 [[clang::sycl_kernel_entry_point(KernelName)]]
-// expected-error@+1 {{ClangIR code gen Not Yet Implemented: SYCL kernel 
caller offload entry point}}
 void kernel_single_task(KernelType kf) { kf(); }
 
 struct KN;
+struct MemberKN;
 struct K {
   void operator()() const {}
 };
 
-void test() { kernel_single_task<KN>(K{}); }
+// A sycl_kernel_entry_point function may also be a non-static member function
+// (Sema only rejects explicit-object members, ctors and dtors). The offload
+// entry point is still a free function and must not run an instance-function
+// prologue.
+struct Invoker {
+  template <typename KernelName, typename KernelType>
+  [[clang::sycl_kernel_entry_point(KernelName)]]
+  void kernel_single_task(KernelType kf) { kf(); }
+};
+
+void test() {
+  kernel_single_task<KN>(K{});
+  Invoker{}.kernel_single_task<MemberKN>(K{});
+}
+
+// The kernel caller entry point is named after the kernel name type (KN), is
+// emitted with the spir_kernel calling convention, and its body calls the
+// kernel functor's operator(). The sycl_kernel_entry_point function and its
+// launch call are not emitted during device compilation.
+// CIR-LABEL: cir.func {{.*}}@_ZTS2KN{{.*}}cc(spir_kernel)
+// CIR:         cir.call @_ZNK1KclEv
+// CIR:         cir.return
+// CIR-NOT:   cir.func {{.*}}@_Z18kernel_single_task
+// CIR-NOT:   cir.call {{.*}}@_Z17sycl_kernel_launch
+
+// The member-function entry point is emitted the same way, as a free function
+// (no implicit `this` parameter).
+// CIR-LABEL: cir.func {{.*}}@_ZTS8MemberKN{{.*}}cc(spir_kernel)
+// CIR:         cir.call @_ZNK1KclEv
+// CIR:         cir.return
+
+// LLVM-OGCG-LABEL: define {{.*}}spir_kernel void @_ZTS2KN
+// LLVM:              call {{.*}}void @_ZNK1KclEv
+// OGCG:              call {{.*}}spir_func void @_ZNK1KclEv
+// LLVM-OGCG:         ret void
+// LLVM-OGCG-NOT:   define {{.*}}@_Z18kernel_single_task
+
+// On ELF, the kernel caller entry point definition is dso_local in CIR,
+// CIR-lowered LLVM IR, and classic CodeGen alike.
+// CIR-ELF:          cir.func {{.*}}dso_local {{.*}}@_ZTS2KN
+// LLVM-OGCG-ELF:    define {{.*}}dso_local {{.*}}void @_ZTS2KN


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to