https://github.com/andykaylor updated 
https://github.com/llvm/llvm-project/pull/233639

>From 99f8798386baef826b6c4cacad64cee7368bd348 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <[email protected]>
Date: Mon, 19 Oct 2026 15:09:44 -0700
Subject: [PATCH 1/2] [CIR][NFC] Refactor calling convention lowering
 classification

This change refactors the CIR calling convention lowering pass to move
classification into a `CIRABIClassifier` class and creates a subclass of that
to perform target-specific handling.

In order to make review easier, I have left as much code as possible in its
previous location. I'll follow up with another PR that moves definitions
into the file where is logically belongs.

Assisted-by: Cursor / claude-opus-5.5
---
 clang/docs/CIR/ABILowering.md                 |   5 +
 .../Dialect/Transforms/CIRABIClassifier.cpp   | 144 ++++++++++
 .../CIR/Dialect/Transforms/CIRABIClassifier.h | 195 ++++++++++++++
 .../Transforms/CIRABIClassifierX86_64.cpp     |  86 ++++++
 .../lib/CIR/Dialect/Transforms/CMakeLists.txt |   2 +
 .../Transforms/CallConvLoweringPass.cpp       | 245 +++++++-----------
 .../x86_64-lang-addrspace-nyi.cir             |   2 +-
 .../abi-lowering/x86_64-variadic-nyi.cir      |   2 +-
 8 files changed, 527 insertions(+), 154 deletions(-)
 create mode 100644 clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.cpp
 create mode 100644 clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.h
 create mode 100644 clang/lib/CIR/Dialect/Transforms/CIRABIClassifierX86_64.cpp

diff --git a/clang/docs/CIR/ABILowering.md b/clang/docs/CIR/ABILowering.md
index bcd628ca8ddda6..8d9a525e98e2e2 100644
--- a/clang/docs/CIR/ABILowering.md
+++ b/clang/docs/CIR/ABILowering.md
@@ -535,6 +535,11 @@ The pass takes one of two driver modes via pass options:
 
 Exactly one of the two options must be set.
 
+Each driver is a `CIRABIClassifier` subclass under
+`clang/lib/CIR/Dialect/Transforms/`. The pass asks the classifier to classify
+each function, each call that passes arguments through an ellipsis, each
+indirect call, and each `cir.va_arg`.
+
 ### Enabling the Pass
 
 `cir-call-conv-lowering` runs by default whenever ClangIR code generation is
diff --git a/clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.cpp 
b/clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.cpp
new file mode 100644
index 00000000000000..bae1bafd5580c8
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.cpp
@@ -0,0 +1,144 @@
+//===- CIRABIClassifier.cpp - ABI classification for CIR 
------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the classification shared by the targets that classify
+// through the LLVM ABI Lowering Library, and the two test drivers that stand
+// in for a target.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRABIClassifier.h"
+#include "TargetLowering/CIRABIRewriteContext.h"
+
+#include "mlir/ABI/Targets/Test/TestTarget.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+
+using namespace mlir;
+using namespace mlir::abi;
+using namespace cir;
+
+std::optional<FunctionClassification>
+CIRABIClassifierCommon::classifyVariadicCall(cir::CIRCallOpInterface call,
+                                             cir::FuncOp callee) {
+  return classifyVariadicCall(call, callee.getFunctionType(),
+                              getTargetInfo(callee));
+}
+
+std::optional<FunctionClassification>
+CIRABIClassifierCommon::classifyIndirectCall(cir::CIRCallOpInterface call) {
+  cir::FuncType funcTy = getIndirectCalleeType(call);
+  const llvm::abi::TargetInfo &targetInfo =
+      getTargetInfo(call->getParentOfType<cir::FuncOp>());
+  if (call.getNumArgOperands() > funcTy.getNumInputs())
+    return classifyVariadicCall(call, funcTy, targetInfo);
+  return classifySignature(funcTy.getReturnType(), funcTy.getInputs(),
+                           requiredArgs(funcTy), targetInfo,
+                           [&]() { return call->emitOpError(); });
+}
+
+namespace {
+
+/// Classifies with the MLIR test ABI target: predictable rules that
+/// approximate x86_64 SysV, used by tests that need a target-independent
+/// driver.
+class TestTargetClassifier final : public CIRABIClassifier {
+public:
+  explicit TestTargetClassifier(const mlir::DataLayout &dl) : dl(dl) {}
+
+  std::optional<FunctionClassification>
+  classifyFunction(cir::FuncOp func) final {
+    return cir::classifyFunction(func, dl, cir::CallConvTarget::Test,
+                                 /*classificationAttrName=*/"");
+  }
+
+  /// The test target classifies only declared parameters.
+  std::optional<FunctionClassification>
+  classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncOp) final {
+    call->emitOpError()
+        << "variadic arguments not yet implemented in CallConvLowering";
+    return std::nullopt;
+  }
+
+  std::optional<FunctionClassification>
+  classifyIndirectCall(cir::CIRCallOpInterface call) final {
+    cir::FuncType funcTy = getIndirectCalleeType(call);
+    if (call.getNumArgOperands() > funcTy.getNumInputs()) {
+      call->emitOpError()
+          << "variadic arguments not yet implemented in CallConvLowering";
+      return std::nullopt;
+    }
+    return withReturnVoidness(mlir::abi::test::classify(funcTy.getInputs(),
+                                                        funcTy.getReturnType(),
+                                                        dl),
+                              funcTy.getReturnType());
+  }
+
+  std::optional<ArgClassification> classifyVAArg(cir::VAArgOp vaArg) final {
+    vaArg->emitOpError()
+        << "not yet implemented in CallConvLowering for the test target";
+    return std::nullopt;
+  }
+
+private:
+  const mlir::DataLayout &dl;
+};
+
+/// Reads a pre-built classification from a function attribute, so a test can
+/// inject any classification (including shapes no target produces) without
+/// depending on a real ABI target.
+class InjectedClassifier final : public CIRABIClassifier {
+public:
+  InjectedClassifier(const mlir::DataLayout &dl, llvm::StringRef attrName)
+      : dl(dl), attrName(attrName) {}
+
+  std::optional<FunctionClassification>
+  classifyFunction(cir::FuncOp func) final {
+    return cir::classifyFunction(func, dl, cir::CallConvTarget::None, 
attrName);
+  }
+
+  /// The injected classification covers a function's declared parameters, so
+  /// it cannot describe an operand passed through an ellipsis.
+  std::optional<FunctionClassification>
+  classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncOp) final {
+    call->emitOpError()
+        << "variadic arguments not yet implemented in CallConvLowering";
+    return std::nullopt;
+  }
+
+  /// Nor can it describe a callee resolved at run time, which names no
+  /// function to read the attribute from.
+  std::optional<FunctionClassification>
+  classifyIndirectCall(cir::CIRCallOpInterface call) final {
+    call->emitOpError() << "indirect call cannot be classified in the "
+                           "'classification-attr' driver mode";
+    return std::nullopt;
+  }
+
+  std::optional<ArgClassification> classifyVAArg(cir::VAArgOp vaArg) final {
+    vaArg->emitOpError() << "cannot be classified in the "
+                            "'classification-attr' driver mode";
+    return std::nullopt;
+  }
+
+private:
+  const mlir::DataLayout &dl;
+  std::string attrName;
+};
+
+} // namespace
+
+std::unique_ptr<CIRABIClassifier>
+cir::createTestTargetABIClassifier(const mlir::DataLayout &dl) {
+  return std::make_unique<TestTargetClassifier>(dl);
+}
+
+std::unique_ptr<CIRABIClassifier>
+cir::createInjectedABIClassifier(const mlir::DataLayout &dl,
+                                 llvm::StringRef attrName) {
+  return std::make_unique<InjectedClassifier>(dl, attrName);
+}
diff --git a/clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.h 
b/clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.h
new file mode 100644
index 00000000000000..aba0722bd62482
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.h
@@ -0,0 +1,195 @@
+//===- CIRABIClassifier.h - ABI classification for CIR ----------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines CIRABIClassifier, the interface CallConvLowering uses to
+// obtain a mlir::abi::FunctionClassification for a CIR signature.
+//
+// CIRABIClassifier is the producer half of CIR's calling-convention lowering.
+// The consumer half is CIRABIRewriteContext, which turns a classification into
+// IR and needs to know nothing about where it came from.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_LIB_CIR_DIALECT_TRANSFORMS_CIRABICLASSIFIER_H
+#define CLANG_LIB_CIR_DIALECT_TRANSFORMS_CIRABICLASSIFIER_H
+
+#include "mlir/ABI/ABIRewriteContext.h"
+#include "mlir/ABI/ABITypeMapper.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/Diagnostics.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/Passes.h"
+#include "llvm/ABI/FunctionInfo.h"
+#include "llvm/ABI/TargetInfo.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <memory>
+#include <optional>
+
+namespace cir {
+
+/// The target-specific settings a classifier needs beyond what it can read
+/// from the module.  Every field names the target it belongs to, because a
+/// classifier for one target ignores the others' settings.
+struct ABIClassifierOptions {
+  // TODO: Make this class target-independent.
+
+  /// The AVX level the x86_64 classifier sizes a native vector at.
+  llvm::abi::X86AVXABILevel x86AvxAbiLevel = llvm::abi::X86AVXABILevel::None;
+
+  /// Whether a function's own recorded target features may raise its x86_64
+  /// AVX level above x86AvxAbiLevel.
+  bool allowsX86TargetAttrAvx = true;
+
+  /// The x86_64 flags whose value depends on the target and the requested ABI
+  /// compatibility version.
+  llvm::abi::X86ABICompatInfo x86AbiCompat;
+};
+
+/// Produces the classification CallConvLowering rewrites a signature from.
+///
+/// A subclass supplies one target's rules, or one of the two test drivers that
+/// stand in for a target.  The pass holds a single instance for the whole
+/// module.  Each method returns std::nullopt after emitting an error on the
+/// operation it was given, including for an operation the subclass does not
+/// support yet.
+class CIRABIClassifier {
+public:
+  virtual ~CIRABIClassifier() = default;
+
+  /// Classify \p func's declared signature.
+  virtual std::optional<mlir::abi::FunctionClassification>
+  classifyFunction(cir::FuncOp func) = 0;
+
+  /// Classify a direct call to the variadic function \p callee that passes
+  /// arguments through the ellipsis.  The classification covers every operand
+  /// of \p call, and classifies the declared parameters the same way as
+  /// classifyFunction(callee).
+  virtual std::optional<mlir::abi::FunctionClassification>
+  classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncOp callee) = 0;
+
+  /// Classify \p call, whose callee is resolved at run time, from the
+  /// signature its callee pointer points to.
+  virtual std::optional<mlir::abi::FunctionClassification>
+  classifyIndirectCall(cir::CIRCallOpInterface call) = 0;
+
+  /// Classify the type fetched by \p vaArg as an unnamed argument with a full
+  /// register budget.
+  virtual std::optional<mlir::abi::ArgClassification>
+  classifyVAArg(cir::VAArgOp vaArg) = 0;
+};
+
+/// Classifies through the LLVM ABI Lowering Library.  The signature's CIR 
types
+/// are mapped to llvm::abi types, the target's TargetInfo classifies them, and
+/// each llvm::abi::ArgInfo is converted to an ArgClassification.
+///
+/// A subclass supplies the TargetInfo and classifies `cir.va_arg`, whose
+/// expansion is specific to each target.
+class CIRABIClassifierCommon : public CIRABIClassifier {
+public:
+  std::optional<mlir::abi::FunctionClassification>
+  classifyFunction(cir::FuncOp func) override;
+
+  /// The call is classified at the callee's features, not the caller's,
+  /// because the pass rewrites the definition and its call sites from one
+  /// classification.  Classic instead arranges every call site from the
+  /// caller and reports a caller whose features disagree with its callee in
+  /// checkFunctionCallABI, which has no equivalent here yet.
+  std::optional<mlir::abi::FunctionClassification>
+  classifyVariadicCall(cir::CIRCallOpInterface call,
+                       cir::FuncOp callee) override;
+
+  /// A callee resolved at run time carries no features of its own, so the
+  /// call is classified at the features of the function containing it, which
+  /// is the declaration classic arranges every call site from.  A call that
+  /// passes arguments through an ellipsis is classified from its own
+  /// operands, as a direct one is.
+  std::optional<mlir::abi::FunctionClassification>
+  classifyIndirectCall(cir::CIRCallOpInterface call) override;
+
+protected:
+  CIRABIClassifierCommon(const mlir::DataLayout &dl, mlir::ModuleOp modOp)
+      : dl(dl), modOp(modOp), typeMapper(dl) {}
+
+  /// The library classifier for a function whose recorded target features
+  /// may refine the ABI rules, or for the module's rules when
+  /// \p featureSource is null.
+  virtual const llvm::abi::TargetInfo &
+  getTargetInfo(cir::FuncOp featureSource) = 0;
+
+  /// Classify \p ty, the type fetched by a `cir.va_arg`, as an unnamed
+  /// argument with every argument register free.
+  std::optional<mlir::abi::ArgClassification>
+  classifyVarArgType(mlir::Type ty, const llvm::abi::TargetInfo &targetInfo,
+                     llvm::function_ref<mlir::InFlightDiagnostic()> emitError);
+
+  const mlir::DataLayout &dl;
+  mlir::ModuleOp modOp;
+  mlir::abi::ABITypeMapper typeMapper;
+
+private:
+  /// Classify a signature returning \p retCIR and taking \p inputs, whose
+  /// first \p required entries are declared parameters.
+  std::optional<mlir::abi::FunctionClassification>
+  classifySignature(mlir::Type retCIR, mlir::TypeRange inputs,
+                    llvm::abi::RequiredArgs required,
+                    const llvm::abi::TargetInfo &targetInfo,
+                    llvm::function_ref<mlir::InFlightDiagnostic()> emitError);
+
+  /// Classify \p call, which passes more operands than \p calleeTy declares,
+  /// from the call's operands.
+  std::optional<mlir::abi::FunctionClassification>
+  classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncType calleeTy,
+                       const llvm::abi::TargetInfo &targetInfo);
+};
+
+/// The MLIR test ABI target's classifier, whose predictable rules approximate
+/// x86_64 SysV.
+std::unique_ptr<CIRABIClassifier>
+createTestTargetABIClassifier(const mlir::DataLayout &dl);
+
+/// A classifier that reads each function's classification from the
+/// DictionaryAttr named \p attrName.
+std::unique_ptr<CIRABIClassifier>
+createInjectedABIClassifier(const mlir::DataLayout &dl,
+                            llvm::StringRef attrName);
+
+/// The x86_64 System V classifier.
+std::unique_ptr<CIRABIClassifier>
+createX86_64ABIClassifier(const mlir::DataLayout &dl, mlir::ModuleOp modOp,
+                          const ABIClassifierOptions &options);
+
+//===----------------------------------------------------------------------===//
+// Classification helpers defined in CallConvLoweringPass.cpp
+//===----------------------------------------------------------------------===//
+
+/// Record on \p fc whether \p returnType is CIR's void.
+std::optional<mlir::abi::FunctionClassification>
+withReturnVoidness(std::optional<mlir::abi::FunctionClassification> fc,
+                   mlir::Type returnType);
+
+/// Classify \p func with the test target, or from the attribute named
+/// \p classificationAttrName when that is non-empty.
+std::optional<mlir::abi::FunctionClassification>
+classifyFunction(cir::FuncOp func, const mlir::DataLayout &dl,
+                 cir::CallConvTarget target,
+                 llvm::StringRef classificationAttrName);
+
+/// Where \p fnTy's declared parameters end and its ellipsis arguments begin.
+llvm::abi::RequiredArgs requiredArgs(cir::FuncType fnTy);
+
+/// The AVX level to classify \p func at: \p base, raised if the function's own
+/// recorded feature list enables a wider vector.
+llvm::abi::X86AVXABILevel funcAvxLevel(cir::FuncOp func,
+                                       llvm::abi::X86AVXABILevel base);
+
+} // namespace cir
+
+#endif // CLANG_LIB_CIR_DIALECT_TRANSFORMS_CIRABICLASSIFIER_H
diff --git a/clang/lib/CIR/Dialect/Transforms/CIRABIClassifierX86_64.cpp 
b/clang/lib/CIR/Dialect/Transforms/CIRABIClassifierX86_64.cpp
new file mode 100644
index 00000000000000..9d1f02b10dc22d
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Transforms/CIRABIClassifierX86_64.cpp
@@ -0,0 +1,86 @@
+//===- CIRABIClassifierX86_64.cpp - x86_64 System V classification 
--------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the x86_64 System V classifier, which classifies with
+// the LLVM ABI Lowering Library's SysV x86_64 target.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRABIClassifier.h"
+
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+
+#include <array>
+
+using namespace mlir;
+using namespace mlir::abi;
+using namespace cir;
+
+namespace {
+
+class X86_64ABIClassifier final : public CIRABIClassifierCommon {
+public:
+  X86_64ABIClassifier(const mlir::DataLayout &dl, mlir::ModuleOp modOp,
+                      const ABIClassifierOptions &options)
+      : CIRABIClassifierCommon(dl, modOp), 
baseAvxLevel(options.x86AvxAbiLevel),
+        allowsTargetAttrAvx(options.allowsX86TargetAttrAvx),
+        abiCompat(options.x86AbiCompat) {}
+
+  /// cir.va_arg is expanded into the SysV register-save-area / overflow-area
+  /// sequence, which reads the fetched type's classification as an unnamed
+  /// argument, as classic's X86_64ABIInfo::EmitVAArg does.
+  std::optional<ArgClassification> classifyVAArg(cir::VAArgOp vaArg) override {
+    return classifyVarArgType(
+        vaArg.getType(), getTargetInfo(vaArg->getParentOfType<cir::FuncOp>()),
+        [&]() { return vaArg->emitOpError(); });
+  }
+
+protected:
+  /// The AVX level starts at the module's and may be raised by
+  /// \p featureSource's recorded target features.
+  const llvm::abi::TargetInfo &
+  getTargetInfo(cir::FuncOp featureSource) override;
+
+private:
+  /// One library classifier per AVX level, built on first use.  A
+  /// per-function target attribute can raise the level above the module's.
+  static constexpr unsigned numAvxLevels =
+      static_cast<unsigned>(llvm::abi::X86AVXABILevel::Last) + 1;
+  std::array<std::unique_ptr<llvm::abi::TargetInfo>, numAvxLevels> targets;
+
+  llvm::abi::X86AVXABILevel baseAvxLevel;
+  bool allowsTargetAttrAvx;
+
+  /// The x86_64 flags whose value depends on the target and the requested ABI
+  /// compatibility version.
+  llvm::abi::X86ABICompatInfo abiCompat;
+};
+
+const llvm::abi::TargetInfo &
+X86_64ABIClassifier::getTargetInfo(cir::FuncOp featureSource) {
+  llvm::abi::X86AVXABILevel level = baseAvxLevel;
+  if (allowsTargetAttrAvx && featureSource)
+    level = funcAvxLevel(featureSource, baseAvxLevel);
+  assert(static_cast<unsigned>(level) < numAvxLevels &&
+         "a new X86AVXABILevel must move X86AVXABILevel::Last");
+  std::unique_ptr<llvm::abi::TargetInfo> &slot =
+      targets[static_cast<unsigned>(level)];
+  if (!slot)
+    slot =
+        llvm::abi::createX86_64TargetInfo(typeMapper.getTypeBuilder(), level,
+                                          /*Has64BitPointers=*/true, 
abiCompat);
+  return *slot;
+}
+
+} // namespace
+
+std::unique_ptr<CIRABIClassifier>
+cir::createX86_64ABIClassifier(const mlir::DataLayout &dl, mlir::ModuleOp 
modOp,
+                               const ABIClassifierOptions &options) {
+  return std::make_unique<X86_64ABIClassifier>(dl, modOp, options);
+}
diff --git a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt 
b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
index 614f3608352426..b3d6862c19f670 100644
--- a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
@@ -15,6 +15,8 @@ add_clang_library(MLIRCIRTransforms
   IdiomRecognizer.cpp
   LibOpt.cpp
   RecordTypeConverter.cpp
+  CIRABIClassifier.cpp
+  CIRABIClassifierX86_64.cpp
 
   DEPENDS
   MLIRCIRPassIncGen
diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp 
b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
index 3b9156ee95bb5b..e0ae978b0db8f4 100644
--- a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
@@ -30,6 +30,7 @@
 //
 
//===----------------------------------------------------------------------===//
 
+#include "CIRABIClassifier.h"
 #include "PassDetail.h"
 #include "TargetLowering/CIRABIRewriteContext.h"
 
@@ -66,8 +67,6 @@ namespace mlir {
 #include "clang/CIR/Dialect/Passes.h.inc"
 } // namespace mlir
 
-namespace {
-
 
//===----------------------------------------------------------------------===//
 // x86_64 System V classifier bridge
 //
@@ -349,7 +348,7 @@ static mlir::Type unwrapLongDoubleVectorElement(mlir::Type 
ty) {
   return ty;
 }
 
-/// Map a CIR type to an llvm::abi::Type.  classifyX86_64Function pre-filters
+/// Map a CIR type to an llvm::abi::Type.  classifySignature pre-filters
 /// the signature, so only the scalar and struct/array types handled here can
 /// reach this function.
 static const llvm::abi::Type *mapCIRType(mlir::Type type,
@@ -547,7 +546,7 @@ static const llvm::abi::Type *mapCIRType(mlir::Type type,
       })
       .Default([](mlir::Type) -> const llvm::abi::Type * {
         llvm_unreachable(
-            "mapCIRType: type not pre-filtered by classifyX86_64Function");
+            "mapCIRType: type not pre-filtered by classifySignature");
       });
 }
 
@@ -654,38 +653,36 @@ convertABIArgInfo(const llvm::abi::ArgInfo &info, 
MLIRContext *ctx,
 ///
 /// The only x86_64 rule that reads this boundary sends an unnamed vector wider
 /// than 128 bits to memory.
-static llvm::abi::RequiredArgs requiredArgs(cir::FuncType fnTy) {
+llvm::abi::RequiredArgs cir::requiredArgs(cir::FuncType fnTy) {
   if (!fnTy.isVarArg())
     return llvm::abi::RequiredArgs::All;
   return llvm::abi::RequiredArgs(fnTy.getNumInputs());
 }
 
-/// Classify an x86_64 SysV signature (return type + argument types) using the
-/// LLVM ABI library.  Shared by the cir.func path, the variadic-call path and
-/// the indirect-call path (the latter classifies from the callee function
+/// Classify a signature (return type + argument types) using the LLVM ABI
+/// library.  Shared by the cir.func path, the variadic-call path and the
+/// indirect-call path (the latter classifies from the callee function
 /// pointer's pointee FuncType).  \p required marks where the declared
 /// parameters in \p inputs end.  The classifier treats every argument past 
that
 /// point as passed through an ellipsis.  Returns std::nullopt and emits an NYI
 /// error via \p emitError if the signature uses a type the bridge does not
 /// handle yet.
-static std::optional<FunctionClassification> classifyX86_64Signature(
+std::optional<FunctionClassification> 
CIRABIClassifierCommon::classifySignature(
     mlir::Type retCIR, mlir::TypeRange inputs, llvm::abi::RequiredArgs 
required,
-    MLIRContext *ctx, const DataLayout &dl,
-    mlir::abi::ABITypeMapper &typeMapper,
-    const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp,
+    const llvm::abi::TargetInfo &targetInfo,
     llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
   assert(retCIR && "signature return type must be non-null");
   assert((!required.allowsOptionalArgs() ||
           required.getNumRequiredArgs() <= inputs.size()) &&
          "declared parameters cannot outnumber the classified arguments");
+  MLIRContext *ctx = modOp->getContext();
   bool voidRet = isa<cir::VoidType>(retCIR);
 
   auto reject = [&](mlir::Type t) -> bool {
     if (isSupportedType(t, dl))
       return false;
-    emitError()
-        << "x86_64 calling-convention lowering not yet implemented for type "
-        << t;
+    emitError() << "calling-convention lowering not yet implemented for type "
+                << t;
     return true;
   };
   if (!voidRet && reject(retCIR))
@@ -708,7 +705,7 @@ static std::optional<FunctionClassification> 
classifyX86_64Signature(
   // convertABIArgInfo returns nullopt when the classifier picks a coercion 
this
   // bridge cannot represent.
   auto nyiCoercion = [&](mlir::Type t) {
-    emitError() << "x86_64 calling-convention lowering not yet "
+    emitError() << "calling-convention lowering not yet "
                    "implemented for the ABI coercion of type "
                 << t;
   };
@@ -741,8 +738,8 @@ static std::optional<FunctionClassification> 
classifyX86_64Signature(
 
 /// The AVX level to classify \p func at: \p base, raised if the function's own
 /// recorded feature list enables a wider vector.
-static llvm::abi::X86AVXABILevel funcAvxLevel(cir::FuncOp func,
-                                              llvm::abi::X86AVXABILevel base) {
+llvm::abi::X86AVXABILevel cir::funcAvxLevel(cir::FuncOp func,
+                                            llvm::abi::X86AVXABILevel base) {
   // Only a `target` attribute may raise the level.  A multiversioned function
   // carries a raised feature list too, and must stay at the module's level.
   assert(!cir::MissingFeatures::opFuncMultiVersioning());
@@ -764,32 +761,27 @@ static llvm::abi::X86AVXABILevel funcAvxLevel(cir::FuncOp 
func,
   return avx ? std::max(base, llvm::abi::X86AVXABILevel::AVX) : base;
 }
 
-/// Classify a cir.func for x86_64 SysV using the LLVM ABI library.  Returns
-/// std::nullopt and emits an NYI error if the signature uses a type the bridge
-/// does not handle yet.
-static std::optional<FunctionClassification>
-classifyX86_64Function(cir::FuncOp func, const DataLayout &dl,
-                       mlir::abi::ABITypeMapper &typeMapper,
-                       const llvm::abi::TargetInfo &targetInfo,
-                       ModuleOp modOp) {
+/// Classify a cir.func using the LLVM ABI library.  Returns std::nullopt and
+/// emits an NYI error if the signature uses a type the bridge does not handle
+/// yet.
+std::optional<FunctionClassification>
+CIRABIClassifierCommon::classifyFunction(cir::FuncOp func) {
   cir::FuncType fnTy = func.getFunctionType();
-  return classifyX86_64Signature(fnTy.getReturnType(), fnTy.getInputs(),
-                                 requiredArgs(fnTy), func->getContext(), dl,
-                                 typeMapper, targetInfo, modOp,
-                                 [&]() { return func.emitOpError(); });
+  return classifySignature(fnTy.getReturnType(), fnTy.getInputs(),
+                           requiredArgs(fnTy), getTargetInfo(func),
+                           [&]() { return func.emitOpError(); });
 }
 
 /// Classify the single type fetched by a `cir.va_arg` as an unnamed argument
 /// (RequiredArgs(0)) with a full register budget.  Returns std::nullopt and
 /// emits an NYI error if the type is not one this bridge handles.
-static std::optional<ArgClassification> classifyX86_64VarArgType(
-    mlir::Type ty, MLIRContext *ctx, const DataLayout &dl,
-    mlir::abi::ABITypeMapper &typeMapper,
-    const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp,
+std::optional<ArgClassification> CIRABIClassifierCommon::classifyVarArgType(
+    mlir::Type ty, const llvm::abi::TargetInfo &targetInfo,
     llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
-  std::optional<FunctionClassification> fc = classifyX86_64Signature(
-      cir::VoidType::get(ctx), mlir::TypeRange(ty), llvm::abi::RequiredArgs(0),
-      ctx, dl, typeMapper, targetInfo, modOp, emitError);
+  MLIRContext *ctx = modOp->getContext();
+  std::optional<FunctionClassification> fc =
+      classifySignature(cir::VoidType::get(ctx), mlir::TypeRange(ty),
+                        llvm::abi::RequiredArgs(0), targetInfo, emitError);
   if (!fc)
     return std::nullopt;
   return fc->argInfos[0];
@@ -802,17 +794,16 @@ static std::optional<ArgClassification> 
classifyX86_64VarArgType(
 /// small struct is passed in registers early in the list and in memory once
 /// the integer registers are gone.  Classifying from the call's operands
 /// rather than the callee's signature is what makes that accounting right.
-static std::optional<FunctionClassification> classifyX86_64VariadicCall(
-    cir::CIRCallOpInterface call, cir::FuncType calleeTy, const DataLayout &dl,
-    mlir::abi::ABITypeMapper &typeMapper,
-    const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp) {
+std::optional<FunctionClassification>
+CIRABIClassifierCommon::classifyVariadicCall(
+    cir::CIRCallOpInterface call, cir::FuncType calleeTy,
+    const llvm::abi::TargetInfo &targetInfo) {
   assert(calleeTy.isVarArg() &&
          "only a variadic callee can take more operands than it declares");
   Operation *op = call.getOperation();
-  return classifyX86_64Signature(
+  return classifySignature(
       calleeTy.getReturnType(), call.getArgOperands().getTypes(),
-      requiredArgs(calleeTy), op->getContext(), dl, typeMapper, targetInfo,
-      modOp, [&]() { return op->emitOpError(); });
+      requiredArgs(calleeTy), targetInfo, [&]() { return op->emitOpError(); });
 }
 
 /// Whether \p fc gives the callee access to memory through a pointer the ABI
@@ -855,6 +846,8 @@ static bool classifiesSamePrefix(const 
FunctionClassification &calleeFc,
 }
 #endif
 
+namespace {
+
 struct CallConvLoweringPass
     : public impl::CallConvLoweringBase<CallConvLoweringPass> {
   using CallConvLoweringBase::CallConvLoweringBase;
@@ -872,15 +865,17 @@ struct CallConvLoweringPass
   llvm::abi::X86ABICompatInfo x86AbiCompat;
 };
 
+} // namespace
+
 /// Record on \p fc whether \p returnType is CIR's void.  The x86_64 classifier
 /// answers this itself, but the other two drivers cannot: the test target is
 /// dialect-neutral and has no notion of CIR's void, and the
 /// classification-attr schema carries no return type at all.  Both route
 /// through here so a classification always reaches needsRewrite paired with
 /// the return type it was built from.
-static std::optional<FunctionClassification>
-withReturnVoidness(std::optional<FunctionClassification> fc,
-                   mlir::Type returnType) {
+std::optional<FunctionClassification>
+cir::withReturnVoidness(std::optional<FunctionClassification> fc,
+                        mlir::Type returnType) {
   if (fc)
     fc->returnsVoid = mlir::isa<cir::VoidType>(returnType);
   return fc;
@@ -891,8 +886,9 @@ withReturnVoidness(std::optional<FunctionClassification> fc,
 /// (e.g. injection-driver mode but the function is missing the attribute,
 /// or the attribute is malformed).
 std::optional<FunctionClassification>
-classifyFunction(cir::FuncOp func, const DataLayout &dl,
-                 cir::CallConvTarget target, StringRef classificationAttrName) 
{
+cir::classifyFunction(cir::FuncOp func, const DataLayout &dl,
+                      cir::CallConvTarget target,
+                      StringRef classificationAttrName) {
   ArrayRef<Type> argTypes = func.getFunctionType().getInputs();
   Type returnType = func.getFunctionType().getReturnType();
 
@@ -909,14 +905,37 @@ classifyFunction(cir::FuncOp func, const DataLayout &dl,
                               returnType);
   }
 
-  // The x86_64 target is handled directly in runOnOperation (it needs a shared
-  // ABITypeMapper and TargetInfo), so only the test target reaches here.
+  // The x86_64 target classifies through CIRABIClassifierCommon, so only the
+  // test target reaches here.
   assert(target == cir::CallConvTarget::Test &&
          "classifyFunction only handles the test target");
   return withReturnVoidness(mlir::abi::test::classify(argTypes, returnType, 
dl),
                             returnType);
 }
 
+/// Build the classifier the pass options select.  Exactly one of \p target
+/// and \p classificationAttrName is set, which runOnOperation checks before
+/// calling.
+static std::unique_ptr<CIRABIClassifier>
+createABIClassifier(cir::CallConvTarget target,
+                    StringRef classificationAttrName, const DataLayout &dl,
+                    ModuleOp modOp, const ABIClassifierOptions &options) {
+  if (!classificationAttrName.empty())
+    return createInjectedABIClassifier(dl, classificationAttrName);
+
+  switch (target) {
+  case cir::CallConvTarget::Test:
+    return createTestTargetABIClassifier(dl);
+  case cir::CallConvTarget::X86_64:
+    return createX86_64ABIClassifier(dl, modOp, options);
+  case cir::CallConvTarget::None:
+    break;
+  }
+  llvm_unreachable("an unset driver mode is rejected before this point");
+}
+
+namespace {
+
 /// Find the cir.func declaration matching a direct cir.call / cir.try_call
 /// callee, if any.  Returns nullptr if the callee is indirect or the symbol
 /// cannot be resolved.  Takes a SymbolTable instead of a ModuleOp so the
@@ -966,33 +985,12 @@ void CallConvLoweringPass::runOnOperation() {
       [&] { rewriteCtx.finalizeParameterSlots(); });
   SymbolTable symbolTable(moduleOp);
 
-  // A per-function target attribute can raise the AVX level, so one classifier
-  // per module would misclassify a wide vector in such a function.
-  static constexpr unsigned numAvxLevels =
-      static_cast<unsigned>(llvm::abi::X86AVXABILevel::Last) + 1;
-  bool isX86 = target == cir::CallConvTarget::X86_64;
-  std::optional<mlir::abi::ABITypeMapper> x86TypeMapper;
-  std::array<std::unique_ptr<llvm::abi::TargetInfo>, numAvxLevels> x86Targets;
-  if (isX86)
-    x86TypeMapper.emplace(dl);
-  auto x86TargetFor =
-      [&](llvm::abi::X86AVXABILevel level) -> const llvm::abi::TargetInfo & {
-    assert(static_cast<unsigned>(level) < numAvxLevels &&
-           "a new X86AVXABILevel must move X86AVXABILevel::Last");
-    std::unique_ptr<llvm::abi::TargetInfo> &slot =
-        x86Targets[static_cast<unsigned>(level)];
-    if (!slot)
-      slot = llvm::abi::createX86_64TargetInfo(
-          x86TypeMapper->getTypeBuilder(), level,
-          /*Has64BitPointers=*/true, x86AbiCompat);
-    return *slot;
-  };
-  llvm::abi::X86AVXABILevel baseAvxLevel = x86AvxAbiLevel.getValue();
-  auto avxLevelFor = [&](cir::FuncOp func) -> llvm::abi::X86AVXABILevel {
-    if (!allowsX86TargetAttrAvx || !func)
-      return baseAvxLevel;
-    return funcAvxLevel(func, baseAvxLevel);
-  };
+  cir::ABIClassifierOptions classifierOptions;
+  classifierOptions.x86AvxAbiLevel = x86AvxAbiLevel;
+  classifierOptions.allowsX86TargetAttrAvx = allowsX86TargetAttrAvx;
+  classifierOptions.x86AbiCompat = x86AbiCompat;
+  std::unique_ptr<cir::CIRABIClassifier> classifier = createABIClassifier(
+      target, classificationAttr, dl, moduleOp, classifierOptions);
 
   // Classify every cir.func up front.  No IR mutation happens here, so
   // later walks can consult any function's classification regardless of
@@ -1009,12 +1007,7 @@ void CallConvLoweringPass::runOnOperation() {
         (hasIncompleteRecordByValue(fnTy.getReturnType()) ||
          llvm::any_of(fnTy.getInputs(), hasIncompleteRecordByValue)))
       return;
-    std::optional<FunctionClassification> fc;
-    if (isX86)
-      fc = classifyX86_64Function(f, dl, *x86TypeMapper,
-                                  x86TargetFor(avxLevelFor(f)), moduleOp);
-    else
-      fc = classifyFunction(f, dl, target, classificationAttr);
+    std::optional<FunctionClassification> fc = classifier->classifyFunction(f);
     if (!fc) {
       anyFailed = true;
       return;
@@ -1049,11 +1042,8 @@ void CallConvLoweringPass::runOnOperation() {
       return;
     callers[callee].push_back(op);
 
-    // Only the x86_64 driver classifies per call site.  Under the other
-    // drivers the classification comes from a fixed per-function source, so
-    // such a call stays short a classification and rewriteCallSite reports it.
     cir::FuncType calleeTy = callee.getFunctionType();
-    if (!isX86 || call.getNumArgOperands() <= calleeTy.getNumInputs())
+    if (call.getNumArgOperands() <= calleeTy.getNumInputs())
       return;
     // A callee declared without a prototype also takes more operands than it
     // declares, and the verifier allows it.  Those extra arguments are named
@@ -1065,14 +1055,8 @@ void CallConvLoweringPass::runOnOperation() {
       anyFailed = true;
       return;
     }
-    // The callee's level, not the caller's: this pass rewrites the definition
-    // and its call sites from one classification, so they have to agree.
-    // Classic instead arranges every call site from the caller and reports a
-    // caller whose level disagrees with its callee in checkFunctionCallABI,
-    // which has no equivalent here yet.
     std::optional<FunctionClassification> fc =
-        classifyX86_64VariadicCall(call, calleeTy, dl, *x86TypeMapper,
-                                   x86TargetFor(avxLevelFor(callee)), 
moduleOp);
+        classifier->classifyVariadicCall(call, callee);
     if (!fc) {
       anyFailed = true;
       return;
@@ -1175,45 +1159,8 @@ void CallConvLoweringPass::runOnOperation() {
       indirectCalls.push_back(c);
   });
   for (cir::CIRCallOpInterface c : indirectCalls) {
-    // classification-attr mode injects a per-function classification, which
-    // cannot describe a callee resolved at run time.  Report it rather than
-    // leave the indirect call unrewritten while direct calls are coerced.
-    if (!classificationAttr.empty()) {
-      c->emitOpError() << "indirect call cannot be classified in the "
-                          "'classification-attr' driver mode";
-      signalPassFailure();
-      return;
-    }
-    cir::FuncType funcTy = getIndirectCalleeType(c);
-    auto classifySignature =
-        [&](mlir::TypeRange argTypes) -> std::optional<FunctionClassification> 
{
-      // A callee resolved at run time carries no features of its own, so the
-      // level comes from the function containing the call, which is the
-      // declaration classic arranges every call site from.
-      if (isX86)
-        return classifyX86_64Signature(
-            funcTy.getReturnType(), argTypes, requiredArgs(funcTy), ctx, dl,
-            *x86TypeMapper,
-            x86TargetFor(avxLevelFor(c->getParentOfType<cir::FuncOp>())),
-            moduleOp, [&]() { return c->emitOpError(); });
-      return withReturnVoidness(
-          mlir::abi::test::classify(argTypes, funcTy.getReturnType(), dl),
-          funcTy.getReturnType());
-    };
-
-    // An argument passed through an ellipsis has no counterpart in the
-    // pointee's parameter list.  On x86_64 such a call is classified from its
-    // own operands, as a direct one is.  Under target=test it is classified
-    // from the pointee alone, and rewriteCallSite reports the call.
-    bool classifyCallSite =
-        isX86 && c.getNumArgOperands() > funcTy.getNumInputs();
     std::optional<FunctionClassification> fc =
-        classifyCallSite
-            ? classifyX86_64VariadicCall(
-                  c, funcTy, dl, *x86TypeMapper,
-                  x86TargetFor(avxLevelFor(c->getParentOfType<cir::FuncOp>())),
-                  moduleOp)
-            : classifySignature(funcTy.getInputs());
+        classifier->classifyIndirectCall(c);
     if (!fc) {
       signalPassFailure();
       return;
@@ -1226,25 +1173,19 @@ void CallConvLoweringPass::runOnOperation() {
     }
   }
 
-  if (isX86) {
-    // Collect the fetches before rewriting any, because rewriting one erases
-    // it, and a live walk holds the op it is about to visit next.
-    SmallVector<cir::VAArgOp> vaArgs;
-    moduleOp.walk([&](cir::VAArgOp v) { vaArgs.push_back(v); });
-    for (cir::VAArgOp v : vaArgs) {
-      cir::FuncOp enclosing = v->getParentOfType<cir::FuncOp>();
-      std::optional<ArgClassification> ac = classifyX86_64VarArgType(
-          v.getType(), ctx, dl, *x86TypeMapper,
-          x86TargetFor(avxLevelFor(enclosing)), moduleOp,
-          [&]() { return v->emitOpError(); });
-      if (!ac) {
-        signalPassFailure();
-        return;
-      }
-      if (failed(rewriteCtx.rewriteVAArg(v.getOperation(), *ac, builder))) {
-        signalPassFailure();
-        return;
-      }
+  // Collect the fetches before rewriting any, because rewriting one erases
+  // it, and a live walk holds the op it is about to visit next.
+  SmallVector<cir::VAArgOp> vaArgs;
+  moduleOp.walk([&](cir::VAArgOp v) { vaArgs.push_back(v); });
+  for (cir::VAArgOp v : vaArgs) {
+    std::optional<ArgClassification> ac = classifier->classifyVAArg(v);
+    if (!ac) {
+      signalPassFailure();
+      return;
+    }
+    if (failed(rewriteCtx.rewriteVAArg(v.getOperation(), *ac, builder))) {
+      signalPassFailure();
+      return;
     }
   }
 }
diff --git 
a/clang/test/CIR/Transforms/abi-lowering/x86_64-lang-addrspace-nyi.cir 
b/clang/test/CIR/Transforms/abi-lowering/x86_64-lang-addrspace-nyi.cir
index a8350b421757dc..285df67e53c838 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-lang-addrspace-nyi.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-lang-addrspace-nyi.cir
@@ -15,4 +15,4 @@ module attributes {
 
 }
 
-// CHECK: op x86_64 calling-convention lowering not yet implemented for type
+// CHECK: op calling-convention lowering not yet implemented for type
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-nyi.cir 
b/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-nyi.cir
index 52a74f07fd2380..a2aab9c43318b8 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-nyi.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-nyi.cir
@@ -44,7 +44,7 @@ module attributes {
   cir.func @indirect_nyi(%arg0: !cir.ptr<!cir.func<(!cir.ptr<!s8i>, ...) -> 
!s32i>>,
                          %arg1: !cir.ptr<!s8i>, %arg2: !cir.ptr<!i96>) {
     %v = cir.load %arg2 : !cir.ptr<!i96>, !i96
-    // CHECK: :[[@LINE+1]]:10: error: 'cir.call' op x86_64 calling-convention 
lowering not yet implemented for type '!cir.int<s, 96>'
+    // CHECK: :[[@LINE+1]]:10: error: 'cir.call' op calling-convention 
lowering not yet implemented for type '!cir.int<s, 96>'
     %0 = cir.call %arg0(%arg1, %v)
         : (!cir.ptr<!cir.func<(!cir.ptr<!s8i>, ...) -> !s32i>>, 
!cir.ptr<!s8i>, !i96) -> !s32i
     cir.return

>From 42479546d224be3ad4929d67ed8334b81e759d70 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <[email protected]>
Date: Tue, 20 Oct 2026 15:50:47 -0700
Subject: [PATCH 2/2] Clean up getTargetInfo handling

---
 clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.h         | 3 +--
 clang/lib/CIR/Dialect/Transforms/CIRABIClassifierX86_64.cpp | 3 ++-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.h 
b/clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.h
index aba0722bd62482..d1799eccb37be5 100644
--- a/clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.h
+++ b/clang/lib/CIR/Dialect/Transforms/CIRABIClassifier.h
@@ -119,8 +119,7 @@ class CIRABIClassifierCommon : public CIRABIClassifier {
       : dl(dl), modOp(modOp), typeMapper(dl) {}
 
   /// The library classifier for a function whose recorded target features
-  /// may refine the ABI rules, or for the module's rules when
-  /// \p featureSource is null.
+  /// may refine the ABI rules.
   virtual const llvm::abi::TargetInfo &
   getTargetInfo(cir::FuncOp featureSource) = 0;
 
diff --git a/clang/lib/CIR/Dialect/Transforms/CIRABIClassifierX86_64.cpp 
b/clang/lib/CIR/Dialect/Transforms/CIRABIClassifierX86_64.cpp
index 9d1f02b10dc22d..14dabde136e78c 100644
--- a/clang/lib/CIR/Dialect/Transforms/CIRABIClassifierX86_64.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CIRABIClassifierX86_64.cpp
@@ -64,7 +64,8 @@ class X86_64ABIClassifier final : public 
CIRABIClassifierCommon {
 const llvm::abi::TargetInfo &
 X86_64ABIClassifier::getTargetInfo(cir::FuncOp featureSource) {
   llvm::abi::X86AVXABILevel level = baseAvxLevel;
-  if (allowsTargetAttrAvx && featureSource)
+  assert(featureSource && "function required for getTargetInfo");
+  if (allowsTargetAttrAvx)
     level = funcAvxLevel(featureSource, baseAvxLevel);
   assert(static_cast<unsigned>(level) < numAvxLevels &&
          "a new X86AVXABILevel must move X86AVXABILevel::Last");

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

Reply via email to