[llvm-branch-commits] [mlir] cceb1bf - [mlir][CAPI] Introduce standard source layout for mlir-c dialect registration.

Stella Laurenzo via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Jan 11 12:40:45 PST 2021


Author: Stella Laurenzo
Date: 2021-01-11T12:35:49-08:00
New Revision: cceb1bfcbbc4ee2e9cc56b76a4acc4cd52968791

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

LOG: [mlir][CAPI] Introduce standard source layout for mlir-c dialect registration.

* Registers a small set of sample dialects.
* NFC with respect to existing C-API symbols but some headers have been moved down a level to the Dialect/ sub-directory.
* Adds an additional entry point per dialect that is needed for dynamic discovery/loading.
* See discussion: https://llvm.discourse.group/t/dialects-and-the-c-api/2306/16

Differential Revision: https://reviews.llvm.org/D94370

Added: 
    mlir/include/mlir-c/Dialect/Linalg.h
    mlir/include/mlir-c/Dialect/SCF.h
    mlir/include/mlir-c/Dialect/Shape.h
    mlir/include/mlir-c/Dialect/Standard.h
    mlir/include/mlir-c/Dialect/Tensor.h
    mlir/include/mlir/CAPI/Registration.h
    mlir/lib/CAPI/Dialect/CMakeLists.txt
    mlir/lib/CAPI/Dialect/Linalg.cpp
    mlir/lib/CAPI/Dialect/SCF.cpp
    mlir/lib/CAPI/Dialect/Shape.cpp
    mlir/lib/CAPI/Dialect/Standard.cpp
    mlir/lib/CAPI/Dialect/Tensor.cpp

Modified: 
    mlir/include/mlir-c/Registration.h
    mlir/lib/CAPI/CMakeLists.txt
    mlir/test/CAPI/ir.c

Removed: 
    mlir/include/mlir-c/StandardDialect.h
    mlir/lib/CAPI/Standard/CMakeLists.txt
    mlir/lib/CAPI/Standard/StandardDialect.cpp


################################################################################
diff  --git a/mlir/include/mlir-c/Dialect/Linalg.h b/mlir/include/mlir-c/Dialect/Linalg.h
new file mode 100644
index 0000000000000..56258ac19af45
--- /dev/null
+++ b/mlir/include/mlir-c/Dialect/Linalg.h
@@ -0,0 +1,25 @@
+//===-- mlir-c/Dialect/Linalg.h - C API for Linalg dialect --------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
+// Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_C_DIALECT_LINALG_H
+#define MLIR_C_DIALECT_LINALG_H
+
+#include "mlir-c/Registration.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(Linalg, linalg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MLIR_C_DIALECT_LINALG_H

diff  --git a/mlir/include/mlir-c/Dialect/SCF.h b/mlir/include/mlir-c/Dialect/SCF.h
new file mode 100644
index 0000000000000..c1b25677969bf
--- /dev/null
+++ b/mlir/include/mlir-c/Dialect/SCF.h
@@ -0,0 +1,25 @@
+//===-- mlir-c/Dialect/SCF.h - C API for SCF dialect --------------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
+// Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_C_DIALECT_SCF_H
+#define MLIR_C_DIALECT_SCF_H
+
+#include "mlir-c/Registration.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(SCF, scf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MLIR_C_DIALECT_SCF_H

diff  --git a/mlir/include/mlir-c/Dialect/Shape.h b/mlir/include/mlir-c/Dialect/Shape.h
new file mode 100644
index 0000000000000..f64da801610b2
--- /dev/null
+++ b/mlir/include/mlir-c/Dialect/Shape.h
@@ -0,0 +1,25 @@
+//===-- mlir-c/Dialect/Shape.h - C API for Shape dialect ----------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
+// Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_C_DIALECT_SHAPE_H
+#define MLIR_C_DIALECT_SHAPE_H
+
+#include "mlir-c/Registration.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(Shape, shape);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MLIR_C_DIALECT_SHAPE_H

diff  --git a/mlir/include/mlir-c/StandardDialect.h b/mlir/include/mlir-c/Dialect/Standard.h
similarity index 52%
rename from mlir/include/mlir-c/StandardDialect.h
rename to mlir/include/mlir-c/Dialect/Standard.h
index 191872103104e..200962177cb95 100644
--- a/mlir/include/mlir-c/StandardDialect.h
+++ b/mlir/include/mlir-c/Dialect/Standard.h
@@ -1,4 +1,4 @@
-//===-- mlir-c/StandardDialect.h - C API for Standard dialect -----*- C -*-===//
+//===-- mlir-c/Dialect/Standard.h - C API for Standard dialect ----*- C -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM
 // Exceptions.
@@ -15,29 +15,19 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef MLIR_C_STANDARDDIALECT_H
-#define MLIR_C_STANDARDDIALECT_H
+#ifndef MLIR_C_DIALECT_STANDARD_H
+#define MLIR_C_DIALECT_STANDARD_H
 
-#include "mlir-c/IR.h"
+#include "mlir-c/Registration.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/** Registers the Standard dialect with the given context. This allows the
- * dialect to be loaded dynamically if needed when parsing. */
-MLIR_CAPI_EXPORTED void mlirContextRegisterStandardDialect(MlirContext context);
-
-/** Loads the Standard dialect into the given context. The dialect does _not_
- * have to be registered in advance. */
-MLIR_CAPI_EXPORTED MlirDialect
-mlirContextLoadStandardDialect(MlirContext context);
-
-/// Returns the namespace of the Standard dialect, suitable for loading it.
-MLIR_CAPI_EXPORTED MlirStringRef mlirStandardDialectGetNamespace();
+MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(Standard, std);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif // MLIR_C_STANDARDDIALECT_H
+#endif // MLIR_C_DIALECT_STANDARD_H

diff  --git a/mlir/include/mlir-c/Dialect/Tensor.h b/mlir/include/mlir-c/Dialect/Tensor.h
new file mode 100644
index 0000000000000..f749782486f1b
--- /dev/null
+++ b/mlir/include/mlir-c/Dialect/Tensor.h
@@ -0,0 +1,25 @@
+//===-- mlir-c/Dialect/Tensor.h - C API for Tensor dialect --------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
+// Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_C_DIALECT_TENSOR_H
+#define MLIR_C_DIALECT_TENSOR_H
+
+#include "mlir-c/Registration.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(Tensor, tensor);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MLIR_C_DIALECT_TENSOR_H

diff  --git a/mlir/include/mlir-c/Registration.h b/mlir/include/mlir-c/Registration.h
index 6bb885ef642ae..7fde05d50bd97 100644
--- a/mlir/include/mlir-c/Registration.h
+++ b/mlir/include/mlir-c/Registration.h
@@ -16,9 +16,58 @@
 extern "C" {
 #endif
 
-/** Registers all dialects known to core MLIR with the provided Context.
- * This is needed before creating IR for these Dialects.
- */
+//===----------------------------------------------------------------------===//
+// Dialect registration declarations.
+// Registration entry-points for each dialect are declared using the common
+// MLIR_DECLARE_DIALECT_REGISTRATION_CAPI macro, which takes the dialect
+// API name (i.e. "Standard", "Tensor", "Linalg") and namespace (i.e. "std",
+// "tensor", "linalg"). The following declarations are produced:
+//
+//   /// Registers the dialect with the given context. This allows the
+//   /// dialect to be loaded dynamically if needed when parsing. */
+//   void mlirContextRegister{NAME}Dialect(MlirContext);
+//
+//   /// Loads the dialect into the given context. The dialect does _not_
+//   /// have to be registered in advance.
+//   MlirDialect mlirContextLoad{NAME}Dialect(MlirContext context);
+//
+//   /// Returns the namespace of the Standard dialect, suitable for loading it.
+//   MlirStringRef mlir{NAME}DialectGetNamespace();
+//
+//   /// Gets the above hook methods in struct form for a dialect by namespace.
+//   /// This is intended to facilitate dynamic lookup and registration of
+//   /// dialects via a plugin facility based on shared library symbol lookup.
+//   const MlirDialectRegistrationHooks *mlirGetDialectHooks__{NAMESPACE}__();
+//
+// This is done via a common macro to facilitate future expansion to
+// registration schemes.
+//===----------------------------------------------------------------------===//
+
+#define MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(Name, Namespace)                \
+  MLIR_CAPI_EXPORTED void mlirContextRegister##Name##Dialect(                  \
+      MlirContext context);                                                    \
+  MLIR_CAPI_EXPORTED MlirDialect mlirContextLoad##Name##Dialect(               \
+      MlirContext context);                                                    \
+  MLIR_CAPI_EXPORTED MlirStringRef mlir##Name##DialectGetNamespace();          \
+  MLIR_CAPI_EXPORTED const MlirDialectRegistrationHooks                        \
+      *mlirGetDialectHooks__##Namespace##__()
+
+/// Hooks for dynamic discovery of dialects.
+typedef void (*MlirContextRegisterDialectHook)(MlirContext context);
+typedef MlirDialect (*MlirContextLoadDialectHook)(MlirContext context);
+typedef MlirStringRef (*MlirDialectGetNamespaceHook)();
+
+/// Structure of dialect registration hooks.
+struct MlirDialectRegistrationHooks {
+  MlirContextRegisterDialectHook registerHook;
+  MlirContextLoadDialectHook loadHook;
+  MlirDialectGetNamespaceHook getNamespaceHook;
+};
+typedef struct MlirDialectRegistrationHooks MlirDialectRegistrationHooks;
+
+/// Registers all dialects known to core MLIR with the provided Context.
+/// This is needed before creating IR for these Dialects.
+/// TODO: Remove this function once the real registration API is finished.
 MLIR_CAPI_EXPORTED void mlirRegisterAllDialects(MlirContext context);
 
 #ifdef __cplusplus

diff  --git a/mlir/include/mlir/CAPI/Registration.h b/mlir/include/mlir/CAPI/Registration.h
new file mode 100644
index 0000000000000..da63afb4c515a
--- /dev/null
+++ b/mlir/include/mlir/CAPI/Registration.h
@@ -0,0 +1,40 @@
+//===- Registration.h - C API Registration implementation  ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_CAPI_REGISTRATION_H
+#define MLIR_CAPI_REGISTRATION_H
+
+#include "mlir-c/IR.h"
+#include "mlir-c/Registration.h"
+#include "mlir/CAPI/IR.h"
+#include "mlir/CAPI/Support.h"
+
+//===----------------------------------------------------------------------===//
+// Corrolary to MLIR_DECLARE_CAPI_DIALECT_REGISTRATION that defines an impl.
+// Takes the same name passed to the above and the fully qualified class name
+// of the dialect class.
+//===----------------------------------------------------------------------===//
+
+#define MLIR_DEFINE_CAPI_DIALECT_REGISTRATION(Name, Namespace, ClassName)      \
+  void mlirContextRegister##Name##Dialect(MlirContext context) {               \
+    unwrap(context)->getDialectRegistry().insert<ClassName>();                 \
+  }                                                                            \
+  MlirDialect mlirContextLoad##Name##Dialect(MlirContext context) {            \
+    return wrap(unwrap(context)->getOrLoadDialect<ClassName>());               \
+  }                                                                            \
+  MlirStringRef mlir##Name##DialectGetNamespace() {                            \
+    return wrap(ClassName::getDialectNamespace());                             \
+  }                                                                            \
+  const MlirDialectRegistrationHooks *mlirGetDialectHooks__##Namespace##__() { \
+    static MlirDialectRegistrationHooks hooks = {                              \
+        mlirContextRegister##Name##Dialect, mlirContextLoad##Name##Dialect,    \
+        mlir##Name##DialectGetNamespace};                                      \
+    return &hooks;                                                             \
+  }
+
+#endif // MLIR_CAPI_REGISTRATION_H

diff  --git a/mlir/lib/CAPI/CMakeLists.txt b/mlir/lib/CAPI/CMakeLists.txt
index 8bbee6a74c08f..1ccf46204f9e9 100644
--- a/mlir/lib/CAPI/CMakeLists.txt
+++ b/mlir/lib/CAPI/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_subdirectory(IR)
 add_subdirectory(Registration)
-add_subdirectory(Standard)
+add_subdirectory(Dialect)
 add_subdirectory(Transforms)
 
 

diff  --git a/mlir/lib/CAPI/Dialect/CMakeLists.txt b/mlir/lib/CAPI/Dialect/CMakeLists.txt
new file mode 100644
index 0000000000000..d256309bf8f08
--- /dev/null
+++ b/mlir/lib/CAPI/Dialect/CMakeLists.txt
@@ -0,0 +1,48 @@
+# TODO: Make the check source feature optional as an argument on *_add_library.
+set(LLVM_OPTIONAL_SOURCES
+  Linalg.cpp
+  SCF.cpp
+  Shape.cpp
+  Standard.cpp
+  Tensor.cpp
+)
+
+add_mlir_public_c_api_library(MLIRCAPILinalg
+  Linalg.cpp
+
+  LINK_LIBS PUBLIC
+  MLIRCAPIIR
+  MLIRLinalg
+)
+
+add_mlir_public_c_api_library(MLIRCAPISCF
+  SCF.cpp
+
+  LINK_LIBS PUBLIC
+  MLIRCAPIIR
+  MLIRSCF
+)
+
+add_mlir_public_c_api_library(MLIRCAPIShape
+  Shape.cpp
+
+  LINK_LIBS PUBLIC
+  MLIRCAPIIR
+  MLIRShape
+)
+
+add_mlir_public_c_api_library(MLIRCAPIStandard
+  Standard.cpp
+
+  LINK_LIBS PUBLIC
+  MLIRCAPIIR
+  MLIRStandard
+)
+
+add_mlir_public_c_api_library(MLIRCAPITensor
+  Tensor.cpp
+
+  LINK_LIBS PUBLIC
+  MLIRCAPIIR
+  MLIRTensor
+)

diff  --git a/mlir/lib/CAPI/Dialect/Linalg.cpp b/mlir/lib/CAPI/Dialect/Linalg.cpp
new file mode 100644
index 0000000000000..3e45c41adc72c
--- /dev/null
+++ b/mlir/lib/CAPI/Dialect/Linalg.cpp
@@ -0,0 +1,14 @@
+//===- Linalg.cpp - C Interface for Linalg dialect ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir-c/Dialect/Linalg.h"
+#include "mlir/CAPI/Registration.h"
+#include "mlir/Dialect/Linalg/IR/LinalgOps.h"
+
+MLIR_DEFINE_CAPI_DIALECT_REGISTRATION(Linalg, linalg,
+                                      mlir::linalg::LinalgDialect);

diff  --git a/mlir/lib/CAPI/Dialect/SCF.cpp b/mlir/lib/CAPI/Dialect/SCF.cpp
new file mode 100644
index 0000000000000..f81b010b04e21
--- /dev/null
+++ b/mlir/lib/CAPI/Dialect/SCF.cpp
@@ -0,0 +1,13 @@
+//===- SCF.cpp - C Interface for SCF dialect ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/SCF/SCF.h"
+#include "mlir-c/Dialect/SCF.h"
+#include "mlir/CAPI/Registration.h"
+
+MLIR_DEFINE_CAPI_DIALECT_REGISTRATION(SCF, scf, mlir::scf::SCFDialect);

diff  --git a/mlir/lib/CAPI/Dialect/Shape.cpp b/mlir/lib/CAPI/Dialect/Shape.cpp
new file mode 100644
index 0000000000000..22e20ad8eaaac
--- /dev/null
+++ b/mlir/lib/CAPI/Dialect/Shape.cpp
@@ -0,0 +1,13 @@
+//===- Shape.cpp - C Interface for Shape dialect --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/Shape/IR/Shape.h"
+#include "mlir-c/Dialect/Shape.h"
+#include "mlir/CAPI/Registration.h"
+
+MLIR_DEFINE_CAPI_DIALECT_REGISTRATION(Shape, shape, mlir::shape::ShapeDialect);

diff  --git a/mlir/lib/CAPI/Dialect/Standard.cpp b/mlir/lib/CAPI/Dialect/Standard.cpp
new file mode 100644
index 0000000000000..b611cb85f6f62
--- /dev/null
+++ b/mlir/lib/CAPI/Dialect/Standard.cpp
@@ -0,0 +1,13 @@
+//===- Standard.cpp - C Interface for Standard dialect --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir-c/Dialect/Standard.h"
+#include "mlir/CAPI/Registration.h"
+#include "mlir/Dialect/StandardOps/IR/Ops.h"
+
+MLIR_DEFINE_CAPI_DIALECT_REGISTRATION(Standard, std, mlir::StandardOpsDialect);

diff  --git a/mlir/lib/CAPI/Dialect/Tensor.cpp b/mlir/lib/CAPI/Dialect/Tensor.cpp
new file mode 100644
index 0000000000000..8f336c0bf3c4d
--- /dev/null
+++ b/mlir/lib/CAPI/Dialect/Tensor.cpp
@@ -0,0 +1,14 @@
+//===- Tensor.cpp - C Interface for Tensor dialect ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/Tensor/IR/Tensor.h"
+#include "mlir-c/Dialect/Tensor.h"
+#include "mlir/CAPI/Registration.h"
+
+MLIR_DEFINE_CAPI_DIALECT_REGISTRATION(Tensor, tensor,
+                                      mlir::tensor::TensorDialect);

diff  --git a/mlir/lib/CAPI/Standard/CMakeLists.txt b/mlir/lib/CAPI/Standard/CMakeLists.txt
deleted file mode 100644
index 197fea4ce4b2d..0000000000000
--- a/mlir/lib/CAPI/Standard/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-add_mlir_public_c_api_library(MLIRCAPIStandard
-  StandardDialect.cpp
-
-  LINK_LIBS PUBLIC
-  MLIRCAPIIR
-  MLIRStandard
-)

diff  --git a/mlir/lib/CAPI/Standard/StandardDialect.cpp b/mlir/lib/CAPI/Standard/StandardDialect.cpp
deleted file mode 100644
index f78c9c916873e..0000000000000
--- a/mlir/lib/CAPI/Standard/StandardDialect.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-//===- StandardDialect.cpp - C Interface for Standard dialect -------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "mlir-c/StandardDialect.h"
-#include "mlir-c/IR.h"
-#include "mlir/CAPI/IR.h"
-#include "mlir/CAPI/Support.h"
-#include "mlir/Dialect/StandardOps/IR/Ops.h"
-
-void mlirContextRegisterStandardDialect(MlirContext context) {
-  unwrap(context)->getDialectRegistry().insert<mlir::StandardOpsDialect>();
-}
-
-MlirDialect mlirContextLoadStandardDialect(MlirContext context) {
-  return wrap(unwrap(context)->getOrLoadDialect<mlir::StandardOpsDialect>());
-}
-
-MlirStringRef mlirStandardDialectGetNamespace() {
-  return wrap(mlir::StandardOpsDialect::getDialectNamespace());
-}

diff  --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c
index b4775978b17c4..5a222cef0bacc 100644
--- a/mlir/test/CAPI/ir.c
+++ b/mlir/test/CAPI/ir.c
@@ -16,8 +16,8 @@
 #include "mlir-c/BuiltinAttributes.h"
 #include "mlir-c/BuiltinTypes.h"
 #include "mlir-c/Diagnostics.h"
+#include "mlir-c/Dialect/Standard.h"
 #include "mlir-c/Registration.h"
-#include "mlir-c/StandardDialect.h"
 
 #include <assert.h>
 #include <math.h>


        


More information about the llvm-branch-commits mailing list