[clang] [mlir] [CIR] Add Direct coerce-in-registers + cir.reinterpret_cast op (PR #195879)
via cfe-commits
cfe-commits at lists.llvm.org
Tue May 5 09:30:33 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: adams381
<details>
<summary>Changes</summary>
Fourth PR in the split of #<!-- -->192119/#<!-- -->192124. Implements the
Direct-with-coercion path in CallConvLowering and picks off
andykaylor's five inline review comments from the original PR.
The new cir.reinterpret_cast op is for same-bit-width in-register
reinterpretation (vector<2 x float> <-> complex<float>).
emitCoercion uses it when source and destination differ only in
vector-vs-non-vector shape and have identical bit width, instead
of going through memory. For everything else (records, or shape
doesn't match) the helper still does alloca/store/ptr-cast/load.
Andy's comments, in order:
- Temporary alloca alignment is now max(srcAlign, dstAlign) from
DataLayout instead of hardcoded.
- The alloca lives in the entry block via InsertionGuard so it
composes with HoistAllocas regardless of pipeline order.
- isVolatile kept as UnitAttr-absence with an inline comment.
- vector<->complex now uses cir.reinterpret_cast.
- Memory path has three new .cir tests covering it.
CallConvLowering needed splitting into three phases
(function-def coercion / call-site rewriting / Ignore cleanup)
because block-arg type changes from Direct-with-coerce confused
the earlier ordering: Ignore'd args were getting alloca/load
chains synthesized for call-site uses that were about to be
dropped anyway.
LowerToLLVM gets a stub for the new op: bitcast for same-shape
converted types, error-with-message for aggregates. We don't
produce aggregates from CallConvLowering today, so the error
path is only reachable from hand-written IR; follow-up patch can
add an extract/insert lowering if needed.
Co-authored-by: Cursor <cursoragent@<!-- -->cursor.com>
---
Patch is 100.75 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/195879.diff
32 Files Affected:
- (modified) clang/docs/CIR/ABILowering.rst (+40)
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+48)
- (modified) clang/include/clang/CIR/Dialect/Passes.h (+1)
- (modified) clang/include/clang/CIR/Dialect/Passes.td (+46-6)
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+22)
- (modified) clang/lib/CIR/Dialect/Transforms/CMakeLists.txt (+3)
- (added) clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp (+198)
- (added) clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp (+570)
- (added) clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.h (+77)
- (modified) clang/lib/CIR/Dialect/Transforms/TargetLowering/CMakeLists.txt (+2)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+39)
- (added) clang/test/CIR/IR/reinterpret-cast.cir (+28)
- (added) clang/test/CIR/Transforms/abi-lowering/Inputs/test-datalayout.cir (+17)
- (added) clang/test/CIR/Transforms/abi-lowering/coerce-int-to-record.cir (+59)
- (added) clang/test/CIR/Transforms/abi-lowering/coerce-record-to-int.cir (+50)
- (added) clang/test/CIR/Transforms/abi-lowering/coerce-record-to-record-via-memory.cir (+34)
- (added) clang/test/CIR/Transforms/abi-lowering/coerce-vector-to-complex-reinterpret.cir (+42)
- (added) clang/test/CIR/Transforms/abi-lowering/datalayout-missing-error.cir (+17)
- (added) clang/test/CIR/Transforms/abi-lowering/declaration-rewrite.cir (+34)
- (added) clang/test/CIR/Transforms/abi-lowering/direct-passthrough-injection.cir (+42)
- (added) clang/test/CIR/Transforms/abi-lowering/direct-passthrough-test-target.cir (+35)
- (added) clang/test/CIR/Transforms/abi-lowering/extend-return.cir (+41)
- (added) clang/test/CIR/Transforms/abi-lowering/extend-signed-arg.cir (+40)
- (added) clang/test/CIR/Transforms/abi-lowering/extend-unsigned-arg.cir (+36)
- (added) clang/test/CIR/Transforms/abi-lowering/ignore-arg.cir (+39)
- (added) clang/test/CIR/Transforms/abi-lowering/ignore-return.cir (+48)
- (modified) clang/tools/cir-opt/cir-opt.cpp (+4)
- (added) mlir/include/mlir/ABI/Targets/Test/TestTarget.h (+98)
- (modified) mlir/lib/ABI/CMakeLists.txt (+1)
- (added) mlir/lib/ABI/Targets/Test/TestTarget.cpp (+251)
- (modified) mlir/unittests/ABI/CMakeLists.txt (+1)
- (added) mlir/unittests/ABI/TestTargetTest.cpp (+317)
``````````diff
diff --git a/clang/docs/CIR/ABILowering.rst b/clang/docs/CIR/ABILowering.rst
index 59f0bb4f9a646..74457be5c8e6d 100644
--- a/clang/docs/CIR/ABILowering.rst
+++ b/clang/docs/CIR/ABILowering.rst
@@ -531,6 +531,46 @@ options or configuration. The dependency direction is: the MLIR ABI pass
depends on ``llvm/lib/ABI``; there is no reverse dependency from the ABI library
to MLIR dialects.
+CIR Pass Pipeline Position
+--------------------------
+
+For the CIR dialect, the calling-convention lowering pass is named
+``cir-call-conv-lowering`` and runs late in the CIR-to-LLVM pipeline:
+
+1. ``cir-target-lowering`` legalizes target-specific operations (e.g.
+ atomic synchronization scopes).
+2. ``cir-cxxabi-lowering`` lowers C++-specific high-level types (member
+ pointers, vtable lookups, etc.) to ABI-specific representations.
+3. ``cir-call-conv-lowering`` rewrites function signatures and call sites
+ to match the target ABI's calling convention rules.
+
+``cir-call-conv-lowering`` requires a ``dlti.dl_spec`` attribute on the
+module so it can query type sizes and alignments through MLIR's
+``DataLayout``. When the attribute is missing, the pass emits a
+diagnostic and fails rather than silently using a default layout.
+
+The pass places any temporary allocas it needs (for argument coercion,
+sret slots, etc.) directly in the function entry block, so it does not
+rely on a subsequent ``cir-hoist-allocas`` run to position them
+correctly. This invariant means ``cir-hoist-allocas`` may run either
+before or after ``cir-call-conv-lowering`` without changing observable
+behavior.
+
+The pass takes one of two driver modes via pass options:
+
+- ``target=<name>`` selects a real ABI target. The first supported value
+ is ``test`` (the MLIR test target in ``mlir/lib/ABI/Targets/Test/``,
+ used for testing the rewriter without depending on the in-progress
+ LLVM ABI library targets). Real targets (``x86_64``, ``aarch64``,
+ ...) will be added as the LLVM ABI library ships them.
+- ``classification-attr=<name>`` reads a pre-built ``FunctionClassifica
+ tion`` from a ``DictionaryAttr`` named ``<name>`` on each ``cir.func``
+ and rewrites accordingly. This driver is for tests that need to
+ exercise rewriter behavior against arbitrary classifications without
+ routing through any real classifier.
+
+Exactly one of the two options must be set.
+
Open Questions
==============
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 97d623ba5e6d9..1f0cb759864f8 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -266,6 +266,54 @@ def CIR_CastOp : CIR_Op<"cast", [
}];
}
+//===----------------------------------------------------------------------===//
+// ReinterpretCastOp
+//===----------------------------------------------------------------------===//
+
+def CIR_ReinterpretCastOp : CIR_Op<"reinterpret_cast", [Pure]> {
+ let summary = "Reinterpret a value as a different same-bit-width type";
+ let description = [{
+ The `cir.reinterpret_cast` operation reinterprets the bits of its source
+ value as a different type, with no IR-level cost. It is used by the
+ calling-convention lowering pass to coerce between same-bit-width types
+ that have an LLVM-IR-level shape mismatch but identical in-register
+ representation -- for example, between `!cir.vector<2 x !cir.float>` and
+ `!cir.complex<!cir.float>`, both of which lower to the same LLVM IR
+ representation but have distinct CIR types.
+
+ Unlike `cir.cast bitcast`, which is overloaded for pointer-to-pointer
+ bitcasts and several other use cases, `cir.reinterpret_cast` is reserved
+ for in-register value reinterpretation only. The result type must
+ differ from the source type; otherwise the op is meaningless and the
+ folder removes it.
+
+ **Invariant** (not currently enforced by the verifier): the source and
+ destination types must have the same bit width per the module's
+ DataLayout, and they must use the same in-register lane order on the
+ target. Producers (e.g. CallConvLowering's coerce-in-registers path)
+ are responsible for ensuring this; a follow-up patch will move the
+ bit-width check into the verifier once the design question of
+ DataLayout-aware op verifiers is resolved.
+
+ Example:
+
+ ```
+ %c = cir.reinterpret_cast %v
+ : !cir.vector<2 x !cir.float> -> !cir.complex<!cir.float>
+ ```
+ }];
+
+ let arguments = (ins CIR_AnyType:$src);
+ let results = (outs CIR_AnyType:$result);
+
+ let assemblyFormat = [{
+ $src `:` type($src) `->` type($result) attr-dict
+ }];
+
+ let hasVerifier = 1;
+ let hasFolder = 1;
+}
+
//===----------------------------------------------------------------------===//
// DynamicCastOp
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/Passes.h b/clang/include/clang/CIR/Dialect/Passes.h
index d441dfcbc6c14..a68f7b621f5d8 100644
--- a/clang/include/clang/CIR/Dialect/Passes.h
+++ b/clang/include/clang/CIR/Dialect/Passes.h
@@ -27,6 +27,7 @@ std::unique_ptr<Pass> createCIRSimplifyPass();
std::unique_ptr<Pass> createCIREHABILoweringPass();
std::unique_ptr<Pass> createCXXABILoweringPass();
std::unique_ptr<Pass> createTargetLoweringPass();
+std::unique_ptr<Pass> createCallConvLoweringPass();
std::unique_ptr<Pass> createHoistAllocasPass();
std::unique_ptr<Pass> createLoweringPreparePass();
std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx);
diff --git a/clang/include/clang/CIR/Dialect/Passes.td b/clang/include/clang/CIR/Dialect/Passes.td
index 32cd182aacec7..cb3c78d590a42 100644
--- a/clang/include/clang/CIR/Dialect/Passes.td
+++ b/clang/include/clang/CIR/Dialect/Passes.td
@@ -108,7 +108,7 @@ def TargetLowering : Pass<"cir-target-lowering", "mlir::ModuleOp"> {
1. The `TargetLowering` pass.
2. The `CXXABILowering` pass.
- 3. The `CallConvLowering` pass (not implemented yet).
+ 3. The `CallConvLowering` pass.
The `TargetLowering` pass acts more like a legalization pass. It ensures
every operation in CIR conforms to the target's constraints. An example
@@ -117,11 +117,11 @@ def TargetLowering : Pass<"cir-target-lowering", "mlir::ModuleOp"> {
any atomic operations with a different synchronization scope would be
transformed to use the system-wide scope in this pass.
- The `CXXABILowering` pass and the (not yet implemented) `CallConvLowering`
- pass transform the CIR according to the target's ABI requirements. The
- former handles all ABI-related lowering except for calling convention
- handling, which is handled specifically in the latter. Example
- transformations that the `CXXABILowering` pass could make include:
+ The `CXXABILowering` pass and the `CallConvLowering` pass transform the
+ CIR according to the target's ABI requirements. The former handles all
+ ABI-related lowering except for calling convention handling, which is
+ handled specifically in the latter. Example transformations that the
+ `CXXABILowering` pass could make include:
- Replace C/C++ types that have an ABI-defined layout with more
fundamental types corresponding to the ABI requirements. For example,
@@ -195,4 +195,44 @@ def IdiomRecognizer : Pass<"cir-idiom-recognizer", "mlir::ModuleOp"> {
let dependentDialects = ["cir::CIRDialect"];
}
+def CallConvLowering : Pass<"cir-call-conv-lowering", "mlir::ModuleOp"> {
+ let summary = "Lower CIR function signatures and call sites to match target ABI";
+ let description = [{
+ This pass rewrites `cir.func` signatures and `cir.call` sites to match the
+ target ABI's calling convention requirements (extension attributes, struct
+ coercion, sret/byval indirect passing, struct flattening, etc.).
+
+ The pass requires a `dlti.dl_spec` attribute on the module so it can query
+ the data layout for sizes and alignments.
+
+ Two driver modes select how each function's classification is computed:
+
+ - `target=<name>` selects an ABI target. Currently only `"test"` (the
+ MLIR test target in `mlir/lib/ABI/Targets/Test/`) is supported. Real
+ targets (x86_64, AArch64, ...) will be added once the LLVM ABI library
+ ships them.
+ - `classification-attr=<name>` reads a `DictionaryAttr` named `<name>`
+ from each `cir.func` and parses it via the test-target injection
+ helper. Used by tests to inject arbitrary classifications without
+ depending on a real ABI target.
+
+ Exactly one of the two options must be set.
+
+ Pipeline position: this pass runs after `CXXABILowering` (so member
+ pointers and similar C++ types are already lowered) and after
+ `HoistAllocas` is unnecessary because this pass places its own temporary
+ allocas in the entry block.
+ }];
+ let constructor = "mlir::createCallConvLoweringPass()";
+ let dependentDialects = ["cir::CIRDialect"];
+ let options = [
+ Option<"target", "target", "std::string", /*default=*/"\"\"",
+ "Target whose ABI rules drive classification (currently: test)">,
+ Option<"classificationAttr", "classification-attr", "std::string",
+ /*default=*/"\"\"",
+ "Function attribute name carrying a pre-built FunctionClassification "
+ "DictionaryAttr (alternative to target=, used by tests)">,
+ ];
+}
+
#endif // CLANG_CIR_DIALECT_PASSES_TD
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 7386819d8fce9..80c3a3ecaea4a 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -821,6 +821,28 @@ static Value tryFoldCastChain(cir::CastOp op) {
return {};
}
+//===----------------------------------------------------------------------===//
+// ReinterpretCastOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::ReinterpretCastOp::verify() {
+ // The op is meaningless for identical types -- the folder is the right
+ // way to remove it -- but we accept it at the verifier level so that
+ // peephole code (e.g. pattern rewriters that round-trip values) doesn't
+ // need a type-equality guard. Producers should still avoid emitting
+ // it for matching types.
+ //
+ // The same-bit-width invariant is documented on the op but not yet
+ // checked here; see the op description for the rationale.
+ return success();
+}
+
+OpFoldResult cir::ReinterpretCastOp::fold(FoldAdaptor adaptor) {
+ if (getSrc().getType() == getType())
+ return getSrc();
+ return {};
+}
+
OpFoldResult cir::CastOp::fold(FoldAdaptor adaptor) {
if (mlir::isa_and_present<cir::PoisonAttr>(adaptor.getSrc())) {
// Propagate poison value
diff --git a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
index 092ccfac7ddb7..b3fa7375eaafa 100644
--- a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
@@ -1,6 +1,7 @@
add_subdirectory(TargetLowering)
add_clang_library(MLIRCIRTransforms
+ CallConvLoweringPass.cpp
CIRCanonicalize.cpp
CIRSimplify.cpp
CXXABILowering.cpp
@@ -19,7 +20,9 @@ add_clang_library(MLIRCIRTransforms
clangAST
clangBasic
+ MLIRABI
MLIRAnalysis
+ MLIRDLTIDialect
MLIRIR
MLIRPass
MLIRTransformUtils
diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
new file mode 100644
index 0000000000000..5131bcfa4316a
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
@@ -0,0 +1,198 @@
+//===- CallConvLoweringPass.cpp - Lower CIR to ABI calling convention ----===//
+//
+// 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 pass walks every cir.func and cir.call in the module, computes a
+// FunctionClassification for it (via either an ABI target or a pre-built
+// classification injected as a function attribute), and dispatches to
+// CIRABIRewriteContext to perform the actual IR rewriting.
+//
+// Two driver modes (mutually exclusive):
+//
+// target=test
+// Use the MLIR test ABI target (mlir/lib/ABI/Targets/Test/) to classify
+// each function. Predictable rules that approximate x86_64 SysV. Real
+// targets (x86_64, AArch64) will be added once the LLVM ABI library
+// ships them.
+//
+// classification-attr=<name>
+// Read a DictionaryAttr named <name> from each cir.func and parse it via
+// mlir::abi::test::parseClassificationAttr. Used by tests to inject any
+// classification (including shapes the test target itself does not
+// produce) without depending on a real ABI target.
+//
+// The pass requires a `dlti.dl_spec` attribute on the module so the
+// classifier can query type sizes and alignments.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PassDetail.h"
+#include "TargetLowering/CIRABIRewriteContext.h"
+
+#include "mlir/ABI/ABIRewriteContext.h"
+#include "mlir/ABI/Targets/Test/TestTarget.h"
+#include "mlir/Dialect/DLTI/DLTI.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+#include "mlir/Pass/Pass.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/Passes.h"
+
+using namespace mlir;
+using namespace mlir::abi;
+using namespace cir;
+
+namespace mlir {
+#define GEN_PASS_DEF_CALLCONVLOWERING
+#include "clang/CIR/Dialect/Passes.h.inc"
+} // namespace mlir
+
+namespace {
+
+struct CallConvLoweringPass
+ : public impl::CallConvLoweringBase<CallConvLoweringPass> {
+ using CallConvLoweringBase::CallConvLoweringBase;
+ void runOnOperation() override;
+};
+
+/// Classify \p func using whichever driver mode is configured. Returns
+/// std::nullopt and emits an error on the function if classification fails
+/// (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, StringRef target,
+ StringRef classificationAttrName) {
+ ArrayRef<Type> argTypes = func.getFunctionType().getInputs();
+ Type returnType = func.getFunctionType().getReturnType();
+
+ if (!classificationAttrName.empty()) {
+ auto attr = func->getAttrOfType<DictionaryAttr>(classificationAttrName);
+ if (!attr) {
+ func.emitOpError()
+ << "missing classification attribute '" << classificationAttrName
+ << "' (CallConvLowering driver mode 'classification-attr')";
+ return std::nullopt;
+ }
+ return mlir::abi::test::parseClassificationAttr(
+ attr, [&]() { return func.emitOpError(); });
+ }
+
+ if (target == "test")
+ return mlir::abi::test::classify(argTypes, returnType, dl);
+
+ func.emitOpError() << "unknown target '" << target << "' (supported: test)";
+ return std::nullopt;
+}
+
+/// Find the cir.func declaration matching a cir.call's callee, if any.
+/// Returns nullptr if the callee is indirect or the symbol cannot be
+/// resolved (in which case the call is left alone).
+cir::FuncOp lookupCallee(cir::CallOp call, ModuleOp module) {
+ FlatSymbolRefAttr callee = call.getCalleeAttr();
+ if (!callee)
+ return nullptr;
+ return module.lookupSymbol<cir::FuncOp>(callee.getValue());
+}
+
+void CallConvLoweringPass::runOnOperation() {
+ ModuleOp module = getOperation();
+ MLIRContext *ctx = &getContext();
+
+ if (target.empty() == classificationAttr.empty()) {
+ module.emitOpError() << "CallConvLowering requires exactly one of "
+ "'target' or 'classification-attr' pass options";
+ signalPassFailure();
+ return;
+ }
+
+ if (!module->hasAttr(DLTIDialect::kDataLayoutAttrName)) {
+ module.emitOpError()
+ << "CallConvLowering requires a DataLayout (dlti.dl_spec attribute "
+ "on the module)";
+ signalPassFailure();
+ return;
+ }
+
+ DataLayout dl(module);
+ CIRABIRewriteContext rewriteCtx(module, dl);
+
+ // Pre-compute classifications for every cir.func so that call-site
+ // rewriting can find them (call site uses callee's classification).
+ llvm::MapVector<cir::FuncOp, FunctionClassification> classifications;
+ bool anyFailed = false;
+ module.walk([&](cir::FuncOp f) {
+ auto fc = classifyFunction(f, dl, target, classificationAttr);
+ if (!fc) {
+ anyFailed = true;
+ return;
+ }
+ classifications.insert({f, std::move(*fc)});
+ });
+ if (anyFailed) {
+ signalPassFailure();
+ return;
+ }
+
+ OpBuilder rewriter(ctx);
+
+ // Three-phase rewrite. Each phase needs the previous one to be complete
+ // across every function before it can run, so they're three separate
+ // sweeps over the module:
+ //
+ // 1. rewriteFunctionDefinition: in-body coercion only. Block-arg
+ // types for Direct-with-coerce / Extend args change here, and
+ // replaceAllUsesExcept routes existing uses (including in-body
+ // cir.call operands) over to the adapted (original-type) value.
+ // Ignore handling and signature finalization are deferred.
+ // 2. rewriteCallSite: each call site coerces args, drops Ignore'd
+ // args, and swaps the call to the lowered signature. Now Ignore'd
+ // block args have no remaining uses.
+ // 3. finalizeFunctionDefinition: erase the now-use-empty Ignore'd
+ // block args, drop Ignore'd return operands, finalize the function
+ // signature, and attach the llvm.signext / llvm.zeroext attrs.
+ //
+ // Splitting (1) and (3) avoids synthesizing dead alloca/load chains
+ // for Ignore'd args whose uses were going to be dropped by (2) anyway.
+
+ for (auto &kv : classifications) {
+ if (failed(rewriteCtx.rewriteFunctionDefinition(kv.first, kv.second,
+ rewriter))) {
+ signalPassFailure();
+ return;
+ }
+ }
+
+ SmallVector<cir::CallOp> calls;
+ module.walk([&](cir::CallOp c) { calls.push_back(c); });
+ for (cir::CallOp call : calls) {
+ cir::FuncOp callee = lookupCallee(call, module);
+ if (!callee)
+ continue;
+ auto it = classifications.find(callee);
+ if (it == classifications.end())
+ continue;
+ if (failed(rewriteCtx.rewriteCallSite(call, it->second, rewriter))) {
+ signalPassFailure();
+ return;
+ }
+ }
+
+ for (auto &kv : classifications) {
+ if (failed(rewriteCtx.finalizeFunctionDefinition(kv.first, kv.second,
+ rewriter))) {
+ signalPassFailure();
+ return;
+ }
+ }
+}
+
+} // namespace
+
+std::unique_ptr<Pass> mlir::createCallConvLoweringPass() {
+ return std::make_unique<CallConvLoweringPass>();
+}
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
new file mode 100644
index 0000000000000..18937d694260b
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
@@ -0,0 +1,570 @@
+//===- CIRABIRewriteContext.cpp - CIR ABI rewrite context ----------------===//
+//
+// 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 "CIRABIRewriteContext.h"
+#include "mlir/IR/Builders.h"
+#include "clang/CIR/Dialect/IR/CIRTypes.h"
+
+using namespace cir;
+using namespace mlir;
+using namespace mlir::abi;
+
+namespace {
+
+bool needsRewrite(const FunctionClassification &fc) {
+ // Direct without coercion is a true pass-through; any other kind (or a
+ // coerced Direct) means the rewriter must touch the IR. Extend is
+ // technically attribute-only at the IR level but still counts because the
+ // attribute attachment changes observable behav...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/195879
More information about the cfe-commits
mailing list