Author: adams381 Date: 2026-03-06T13:58:56-06:00 New Revision: d32ffdea7aa4be414f2efc4a77257bcf0709e8a0
URL: https://github.com/llvm/llvm-project/commit/d32ffdea7aa4be414f2efc4a77257bcf0709e8a0 DIFF: https://github.com/llvm/llvm-project/commit/d32ffdea7aa4be414f2efc4a77257bcf0709e8a0.diff LOG: [CIR] Add MLIR ABI Lowering design document Design document for MLIR dialect-agnostic calling convention lowering that builds on the LLVM ABI Lowering Library (llvm/lib/ABI/) as the single source of truth for ABI classification. Dialects use the library via an adapter layer: ABITypeMapper maps dialect types to abi::Type*, the library classifies arguments and returns, and a dialect-specific ABIRewriteContext applies the decisions back to IR operations. Targets x86_64 and AArch64, with parity against Classic Clang CodeGen validated through differential testing. Added: clang/docs/ClangIRABILowering.md Modified: clang/docs/index.rst Removed: ################################################################################ diff --git a/clang/docs/ClangIRABILowering.md b/clang/docs/ClangIRABILowering.md new file mode 100644 index 0000000000000..9bd42d866c5e1 --- /dev/null +++ b/clang/docs/ClangIRABILowering.md @@ -0,0 +1,545 @@ +# ClangIR ABI Lowering - Design Document + +## 1. Introduction + +This design describes calling convention lowering that builds on the LLVM ABI +Lowering Library in `llvm/lib/ABI/`: we use its `abi::Type*` and target ABI +logic and add an MLIR integration layer (ABITypeMapper, ABI lowering pass, and +dialect rewriters). The framework relies on the LLVM ABI library as the single +source of truth for ABI classification. MLIR dialects use it via an adapter +layer. The design provides a way to perform ABI-compliant calling convention +lowering that can be used by any MLIR dialect that implements the necessary +interfaces. Inputs are high-level function signatures in CIR, FIR, or other +MLIR dialect. Outputs are ABI-lowered signatures and call sites. Lowering +runs as an MLIR pass in the compilation pipeline. + +### 1.1 Design Goals + +Building on the LLVM ABI library and adding an MLIR integration layer avoids +duplicating complex ABI logic across MLIR dialects, reduces maintenance, and +keeps a single source of ABI compliance in `llvm/lib/ABI/`. The separation +between the ABI library (classification) and dialect-specific ABIRewriteContext +(rewriting) enables clearer testing and a straightforward migration path from +the CIR incubator by porting useful algorithms into the ABI library where +appropriate. + +A central goal is that generated code be call-compatible with Classic Clang +CodeGen and other compilers. Parity is with Classic Clang CodeGen output, +not only with the incubator. Success means CIR correctly lowers x86_64 and +AArch64 calling conventions with full ABI compliance using the LLVM ABI library +and MLIR integration layer; FIR can adopt the same infrastructure with minimal +dialect-specific adaptation (e.g. cdecl when calling C from Fortran). ABI +compliance will be validated through diff erential testing against Classic Clang +CodeGen, and performance overhead should remain under 5% compared to a direct, +dialect-specific implementation. Initial scope focuses on fixed-argument +functions; variadic support (varargs) is deferred. + +## 2. Background and Context + +### 2.1 What is Calling Convention Lowering? + +Calling convention lowering transforms high-level function signatures to match +target ABI (Application Binary Interface) requirements. When a function is +declared at the source level with convenient, language-level types, these types +must be translated into the specific register assignments, memory layouts, and +calling sequences that the target architecture expects. For example, on x86_64 +System V ABI, a struct containing two 64-bit integers might be "expanded" into +two separate arguments passed in registers, rather than being passed as a single +aggregate: + +``` +// High-level CIR +func @foo(i32, struct<i64, i64>) -> i32 + +// After ABI lowering +func @foo(i32 %arg0, i64 %arg1, i64 %arg2) -> i32 +// ^ ^ ^ ^ +// | | +--------+ struct expanded into fields +// | +---- first field passed in register +// +---- small integer passed in register +``` + +Calling convention lowering is complex for several reasons: it is highly +target-specific (each architecture has diff erent rules for registers vs. +memory), type-dependent (rules diff er for integers, floats, structs, unions, +arrays), and context-sensitive (varargs, virtual calls, conventions like +vectorcall or preserve_most). The same target may have multiple ABI variants +(e.g. x86_64 System V vs. Windows x64), adding further complexity. + +### 2.2 Existing Implementations + +#### Classic Clang CodeGen + +Classic Clang CodeGen (located in `clang/lib/CodeGen/`) transforms calling +conventions during the AST-to-LLVM-IR lowering process. This implementation is +mature and well-tested, handling all supported targets with comprehensive ABI +coverage. However, it's tightly coupled to both Clang's AST representation and +LLVM IR, making it diff icult to reuse for MLIR-based frontends. + +#### CIR Incubator + +The CIR incubator includes a calling convention lowering pass in +`clang/lib/CIR/Dialect/Transforms/TargetLowering/` that transforms CIR +operations into ABI-lowered CIR operations as an MLIR pass. This implementation +successfully adapted logic from Classic Clang CodeGen to work within the MLIR +framework. However, it relies on CIR-specific types and operations, preventing +reuse by other MLIR dialects. + +#### LLVM ABI Lowering Library + +A 2025 Google Summer of Code project produced [PR +#140112](https://github.com/llvm/llvm-project/pull/140112), which proposes +extracting Clang's ABI logic into a reusable library in `llvm/lib/ABI/`. The +design centers on a shadow type system (`abi::Type*`) separate from both Clang's +AST types and LLVM IR types, enabling the ABI classification algorithms to work +independently of any specific frontend representation. The library includes +abstract `ABIInfo` base classes and target-specific implementations (e.g. +x86_64, BPF) and provides QualTypeMapper for Clang to map `QualType` to +`abi::Type*`. + +Our approach is to complete and extend this library and use it as the single +source of truth for ABI classification. One implementation in one place reduces +duplication, simplifies bug fixes, and creates a path for Classic Clang CodeGen +to use the same logic in the future. MLIR dialects (CIR, FIR, and others) will +use the library via an adapter layer rather than reimplementing ABI logic. + +**Current state.** The x86_64 implementation is largely complete and under +review. AArch64 and some other targets are not yet implemented; there is no +MLIR integration today. The work is being upstreamed in smaller parts (e.g. +[PR 158329](https://github.com/llvm/llvm-project/pull/158329)); progress is +limited by reviewer bandwidth. The overhead of the shadow type system +(converting to and from `abi::Type*`) has been measured at under 0.1% for clang +-O0, so it is negligible for CIR. Our approach therefore depends on the ABI +library being merged upstream or our contributions to it being accepted. + +**Our approach.** The approach is to complete and extend the ABI library (e.g. +AArch64, review feedback, tests) and add an **MLIR integration layer** so that +MLIR dialects can use it: + +- **ABITypeMapper**: maps `mlir::Type` to `abi::Type*`, analogous to + QualTypeMapper for Clang. + +- **MLIR ABI lowering pass**: uses the library's `ABIInfo` for classification, + then performs dialect-specific rewriting via `ABIRewriteContext` for CIR, FIR, + and other dialects. + +The CIR incubator serves as a **reference only** (e.g. for AArch64 algorithms). +We do not upstream the incubator's CIR-specific ABI implementation as the +long-term solution; we port useful algorithms into the ABI library where +appropriate. + +### 2.3 Requirements for MLIR Dialects + +CIR needs to lower C/C++ calling conventions correctly, with initial support for +x86_64 and AArch64 targets. It must handle structs, unions, and complex types, +as well as support instance methods and virtual calls. FIR's initial need is +**cdecl for calling C from Fortran** (C interop); that is in scope. +Fortran-specific ABI semantics (e.g. CHARACTER hidden length parameters, array +descriptors) are out of initial scope; full Fortran ABI lowering is a broader +goal. Both dialects share common requirements: strict target ABI compliance, +efficient lowering with minimal overhead, extensibility for adding new target +architectures, and comprehensive testability and validation capabilities. + +## 3. Proposed Solution + +**Core.** The LLVM ABI library in `llvm/lib/ABI/` performs ABI classification on +`abi::Type*`. It provides `ABIInfo` and target-specific implementations +(x86_64, BPF, and eventually AArch64 and others). This is the single place +where ABI rules are implemented. + +**MLIR side.** To use this library from MLIR dialects we add an integration +layer: (1) **ABITypeMapper** maps `mlir::Type` to `abi::Type*` (analogous to +QualTypeMapper for Clang). (2) A **generic ABI lowering pass** invokes the +library's `ABIInfo` for classification, then (3) performs **dialect-specific +rewriting** via the `ABIRewriteContext` interface—each dialect (CIR, FIR, etc.) +implements only the glue to create its own operations (e.g. `cir.call`, +`fir.call`). Classification logic is shared; operation creation is +dialect-specific. + +The following diagram shows the layering. At the top, the ABI library holds +the ABI logic. In the middle, adapters connect frontends to it: Classic Clang +CodeGen uses QualTypeMapper; MLIR uses ABITypeMapper and the ABI lowering pass. +At the bottom, each dialect implements `ABIRewriteContext` only; FIR is shown as +a consumer for cdecl/C interop (e.g. calling C from Fortran). + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ LLVM ABI Library (llvm/lib/ABI/) │ +│ ABIInfo, abi::Type*, target implementations (X86, AArch64,…) │ +└─────────────────────────────────────────────────────────────────┘ + │ + ┌─────────────────┴─────────────────┐ + │ │ + ▼ ▼ +┌───────────────────────┐ ┌───────────────────────────────┐ +│ Classic CodeGen │ │ MLIR adapter │ +│ QualTypeMapper │ │ ABITypeMapper + ABI pass │ +└───────────────────────┘ └───────────────────────────────┘ + │ + ┌────────────────┼────────────────┐ + │ │ │ + ▼ ▼ ▼ + ┌────────────┐ ┌────────────┐ ┌────────────┐ + │ CIR │ │ FIR │ │ Future │ + │ ABIRewrite │ │ (cdecl/C │ │ Dialects │ + │ Context │ │ interop) │ │ │ + └────────────┘ └────────────┘ └────────────┘ +``` + +## 4. Design Overview + +### 4.1 Architecture Diagram + +The following diagram shows how the design builds on the ABI library (Section +3). At the top, the ABI library holds the classification logic. The middle +layer adapts MLIR to the ABI library: ABITypeMapper converts `mlir::Type` to +`abi::Type*`, and the MLIR ABI lowering pass invokes the library's `ABIInfo` and +uses the classification +to drive rewriting. At the bottom, each dialect implements only +`ABIRewriteContext` for operation creation; there is no separate type +abstraction layer in MLIR for classification—that lives in the ABI library. + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ LLVM ABI Library (llvm/lib/ABI/) — single source of truth │ +│ abi::Type*, ABIInfo, target implementations (X86_64, AArch64, …) │ +│ Input: abi::Type* → Output: classification (ABIArgInfo, etc.) │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ MLIR adapter │ +│ ABITypeMapper (mlir::Type → abi::Type*) + MLIR ABI lowering pass │ +│ (1) Map types (2) Call ABIInfo (3) Drive rewriting from │ +│ classification result │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ┌─────────────────┼─────────────────┐ + ▼ ▼ ▼ + ┌────────────┐ ┌────────────┐ ┌────────────┐ + │ CIR │ │ FIR │ │ Future │ + │ ABIRewrite │ │ ABIRewrite │ │ Dialects │ + │ Context │ │ Context │ │ │ + └────────────┘ └────────────┘ └────────────┘ + Dialect-specific operation creation only (no type + abstraction for classification in MLIR) +``` + +### 4.2 ABI Library, Adapter, and Dialect Layers + +The architecture has three parts. **The ABI library** (`llvm/lib/ABI/`) is the +single source of truth for ABI classification: it operates on `abi::Type*` and +produces classification results (e.g. ABIArgInfo, ABIFunctionInfo). +Target-specific `ABIInfo` implementations (X86_64, AArch64, etc.) live there. +The **adapter layer** is MLIR-specific: ABITypeMapper maps `mlir::Type` to +`abi::Type*`, and the MLIR ABI lowering pass (1) maps types, (2) calls the +library's ABIInfo, and (3) uses the classification to drive rewriting. The +**dialect layer** is only ABIRewriteContext: each dialect (CIR, FIR) implements +operation creation (createFunction, createCall, createExtractValue, etc.). +There is no type abstraction layer in MLIR for classification; type queries for +ABI are performed on `abi::Type*` inside the ABI library. + +### 4.3 Key Components + +The framework is built from the following components. **The ABI library** +(`llvm/lib/ABI/`) provides the single source of truth for ABI classification: +the `abi::Type*` type system, the `ABIInfo` base and target-specific +implementations (e.g. X86_64, AArch64), and the classification result types +(e.g. ABIArgInfo, ABIFunctionInfo). **ABITypeMapper** maps `mlir::Type` to +`abi::Type*` so that MLIR dialect types can be classified by the ABI library. +Dialects with custom types do not need a new interface for this: the mapper +relies on existing MLIR type interfaces (e.g. `DataLayoutTypeInterface`) for +size and alignment, and pattern-matches on standard type categories (integers, +floats, pointers, structs, arrays, vectors) to build `abi::Type*`. +The **MLIR ABI lowering pass** orchestrates the flow: it uses ABITypeMapper, +calls the library's ABIInfo, and drives rewriting from the classification +result. **ABIRewriteContext** is the dialect-specific interface for operation +creation (each dialect implements it to produce e.g. cir.call, fir.call). A +**target registry** (or equivalent) is used to select the appropriate ABIInfo +for the compilation target. There is no ABITypeInterface or separate "ABIInfo +in MLIR"; classification lives entirely in the ABI library. + +### 4.4 ABI Lowering Flow: How the Pieces Fit Together + +This section describes the end-to-end flow of ABI lowering, showing how all +interfaces and components work together. + +#### Step 1: Function Signature Analysis + +The ABI lowering pass begins by analyzing the function signature. Function +operations are identified via MLIR's `FunctionOpInterface`, which provides +access to the function type, argument types, and return types. The pass +extracts the parameter types and return type to prepare them for +classification. At this stage, the types are still in their +high-level, dialect-specific form (e.g., `!cir.struct` for CIR, or `!fir.type` +for FIR). The pass collects these types into a list that will be fed to the +classification logic in the next step. + +``` +Input: func @foo(%arg0: !cir.int<u, 32>, + %arg1: !cir.struct<{!cir.int<u, 64>, + !cir.int<u, 64>}>) -> !cir.int<u, 32> +``` + +#### Step 2: Type Mapping via ABITypeMapper + +For each argument and the return type, the pass maps `mlir::Type` to +`abi::Type*` using ABITypeMapper. The mapper produces the representation that +the library's ABIInfo expects; optionally, it can map back to MLIR types for coercion +types when needed. + +```cpp +// Map dialect types to the library's type system +ABITypeMapper abiTypeMapper(module.getDataLayout()); +abi::Type *arg0Abi = abiTypeMapper.map(arg0Type); // i32 -> IntegerType +abi::Type *arg1Abi = abiTypeMapper.map(arg1Type); // struct -> RecordType +abi::Type *retAbi = abiTypeMapper.map(returnType); +``` + +**Key Point**: Classification runs in the ABI library on `abi::Type*`; ABITypeMapper is +the only bridge from dialect types to that representation. + +#### Step 3: ABI Classification + +The library's target-specific `ABIInfo` (e.g. X86_64) performs classification on +`abi::Type*` and produces the library's classification result (e.g. ABIFunctionInfo +and ABIArgInfo as defined in `llvm/lib/ABI/`): + +```cpp +// The MLIR ABI lowering pass obtains the ABIInfo from the target +// registry based on the module's target triple (see Section 5.2). +llvm::abi::ABIInfo *abiInfo = getABIInfo(); // e.g. X86_64 +llvm::abi::ABIFunctionInfo abiFI; +abiInfo->computeInfo(abiFI, arg0Abi, arg1Abi, retAbi); +// For struct<i64,i64> on x86_64: produces Expand (two i64 args) +``` + +Output: the library's classification (e.g. ABIFunctionInfo) for all arguments and +return: +- `%arg0 (i32)` → Direct (pass as-is) +- `%arg1 (struct)` → Expand (split into two i64 fields) +- Return type → Direct + +#### Step 4: Function Signature Rewriting + +After the library's classification is complete, the pass rewrites the function to match +the ABI requirements using the dialect's `ABIRewriteContext`. The +classification result (from the ABI library) describes the lowered signature; the rewrite +context creates the actual dialect operations. For example, if a struct is +classified as "Expand", the new function signature will have multiple scalar +parameters instead of the single struct parameter. + +```cpp +ABIRewriteContext &ctx = getDialectRewriteContext(); + +// Create new function with lowered signature +FunctionType newType = ...; // (i32, i64, i64) -> i32 +Operation *newFunc = ctx.createFunction(loc, "foo", newType); +``` + +**Key Point**: The original function had signature `(i32, struct) -> i32`, but +the ABI-lowered function has signature `(i32, i64, i64) -> i32` with the struct +expanded into its constituent fields. + +#### Step 5: Argument Expansion + +With the function signature rewritten, the pass updates all call sites to match +the new signature, using the classification from the ABI library to drive rewriting via +`ABIRewriteContext`. For arguments classified as "Expand", the pass breaks down +the aggregate into its constituent parts (e.g. struct into two i64 values). +The rewrite context provides operations to extract fields and construct the new +call with the expanded argument list. + +```cpp +// Original call: call @foo(%val0, %structVal) +// Need to extract struct fields: + +Value field0 = ctx.createExtractValue(loc, structVal, {0}); // extract 1st i64 +Value field1 = ctx.createExtractValue(loc, structVal, {1}); // extract 2nd i64 + +// New call with expanded arguments +ctx.createCall(loc, newFunc, {resultType}, {val0, field0, field1}); +``` + +**Key Point**: `ABIRewriteContext` abstracts the dialect-specific operation +creation, so the lowering logic doesn't need to know about CIR operations. + +#### Step 6: Return Value Handling + +For functions returning large structs (indirect return): + +```cpp +// If return type is classified as Indirect: +Value sretPtr = ctx.createAlloca(loc, retType, alignment); +ctx.createCall(loc, func, {}, {sretPtr, ...otherArgs}); +Value result = ctx.createLoad(loc, sretPtr); +``` + +#### Complete Flow Diagram + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Input: High-Level Function (CIR/FIR/other dialect) │ +│ func @foo(%arg0: i32, %arg1: struct<i64,i64>) -> i32 │ +└────────────────────────┬────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Step 1: Extract Types │ +│ For each parameter: mlir::Type │ +└────────────────────────┬────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Step 2: Map Types (ABITypeMapper → abi::Type*) │ +│ abiTypeMapper.map(argType) → abi::Type* │ +│ └─> Dialect types converted for ABI library │ +└────────────────────────┬────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Step 3: Classify (ABIInfo) │ +│ abiInfo->computeInfo(abiFI, ...) on abi::Type* │ +│ Applies target rules (e.g. x86_64 System V) │ +│ └─> Produces: ABIFunctionInfo / ABIArgInfo │ +└────────────────────────┬────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Step 4: Rewrite Function (ABIRewriteContext) │ +│ Use ABI classification to build lowered signature │ +│ └─> ctx.createFunction(loc, name, newType); (i32, i64, i64) │ +└────────────────────────┬────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Step 5: Rewrite Call Sites (ABIRewriteContext) │ +│ ctx.createExtractValue() - expand struct; ctx.createCall() │ +│ └─> Dialect-specific operation creation │ +└────────────────────────┬────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Output: ABI-Lowered Function │ +│ func @foo(%arg0: i32, %arg1: i64, %arg2: i64) -> i32 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +#### Key Interactions Between Components + +Classification lives in the ABI library: `ABIInfo` operates on `abi::Type*` and produces +classification results (e.g. ABIArgInfo, ABIFunctionInfo). MLIR types reach +the ABI library only via ABITypeMapper, which converts `mlir::Type` to `abi::Type*`. The +lowering pass (1) maps types with ABITypeMapper, (2) calls the library's ABIInfo to +get classification, and (3) uses that result to drive rewriting through the +dialect's ABIRewriteContext. + +ABIRewriteContext consumes the classification (e.g. "Expand" for a struct) and +performs the actual IR changes: createFunction with the lowered signature, +createExtractValue and createCall at call sites. Each dialect implements +ABIRewriteContext to produce its own operations (e.g. cir.call, fir.call). +This keeps classification in one place (the ABI library) and limits dialect code to +operation creation. + +## 5. ABIRewriteContext and Target Registry + +### 5.1 ABIRewriteContext Interface + +ABIRewriteContext is the only dialect-specific layer: CIR and FIR each +implement it to create their own dialect operations (e.g. cir.call, fir.call). +In a module with mixed dialect content, the pass selects the appropriate +ABIRewriteContext for each function based on the dialect of its operations. Classification is +performed by the library's ABIInfo and produces the library's result (e.g. ABIFunctionInfo, +ABIArgInfo); ABIRewriteContext consumes that classification to perform the +actual IR rewriting. The interface defines the operations needed for lowering +(createFunction, createCall, createExtractValue, createLoad, etc.); each dialect +implements these to produce its own operations. ABIRewriteContext is also +responsible for updating ABI-related attributes (e.g. sret, byval, signext, +zeroext, inreg) on the rewritten function signatures and call sites as +indicated by the classification result. + +The interface defines approximately 15-20 methods covering function operations +(`createFunction`, `createCall`), value manipulation (`createCast`, +`createLoad`, `createStore`, `createAlloca`), type coercion (`createBitcast`, +`createTrunc`, `createZExt`, `createSExt`), aggregate operations +(`createExtractValue`, `createInsertValue`, `createGEP`), and housekeeping +(`createFunctionType`, `replaceOp`). This set was chosen based on analyzing the +operations actually needed by existing ABI lowering code: struct expansion +requires extract/insert operations, indirect passing requires alloca and pointer +operations, and coercion requires bitcasts and truncations. + +Each dialect implementing ABI lowering must provide a concrete +`ABIRewriteContext` subclass—estimated at 800-1000 lines of implementation code +that wraps the dialect's builder API. This is a significant but one-time cost: +CIR implements `CIRABIRewriteContext`, FIR implements `FIRABIRewriteContext`, +and any future dialect reuses the shared classification infrastructure by +providing its own context implementation. The alternative—reimplementing the +entire ABI classification logic per dialect—would require 8,000-15,000 lines per +dialect (the combined size of x86_64 and AArch64 classification code plus all +supporting infrastructure), introduce divergent behavior across dialects, and +create a maintenance burden where ABI bug fixes must be propagated to every +dialect independently. + +### 5.2 Target Registry + +We use the library's target selection or registry to obtain the appropriate ABIInfo for +the compilation target (e.g. X86_64, AArch64). We do not introduce a separate +MLIR TargetRegistry unless the MLIR ABI pass needs it for pass 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. + +## 6. Open Questions + +The following items are open for discussion. This section may be revised, +shortened, or removed before final merge. + +### 6.1 How to Handle clang::TargetInfo Dependency in MLIR? + +The CIR incubator currently uses `clang::TargetInfo` to query target-specific +properties needed for ABI decisions, such as pointer width, alignment, +endianness, and calling convention availability. Moving this functionality to +MLIR dialect-agnostic infrastructure raises an architectural question: should +MLIR code depend on a Clang library, or should it use MLIR-based mechanisms? + +Three approaches are under consideration. + +1. Continue using `clang::TargetInfo` directly, accepting an MLIR→Clang + dependency for this target-specific infrastructure. This approach requires + no additional implementation since it already works in the CIR incubator, + and `clang::TargetInfo` provides comprehensive, battle-tested coverage of + all target properties. However, it creates a dependency relationship that + may violate MLIR's architectural principle of being a peer to Clang rather + than dependent on it. + +2. Combine `llvm::Triple` with MLIR's `DataLayoutInterface`, supplemented by + module-level attributes for ABI-specific properties not covered by the data + layout. This approach maintains clean layering with no Clang dependency and + follows MLIR patterns, but requires defining approximately 10-15 additional + attributes and some upfront design work. + +3. Create a new `mlir::target::TargetInfo` abstraction with minimal methods + tailored specifically for ABI needs (approximately 15-20 methods). This + provides clean layering without Clang dependency but requires implementing + and maintaining target-specific code that duplicates some knowledge from + `clang::TargetInfo`. + +Option 2 is recommended as the preferred approach. It maintains MLIR's +independence from Clang, which is important for MLIR's mission to be reusable by +non-Clang frontends like Rust, Julia, and Swift. Target information is input +metadata rather than an output format, so it should be expressible through +MLIR's existing mechanisms rather than requiring external dependencies. Option +3 serves as an acceptable fallback if Option 2 proves insufficient during +prototyping, while Option 1 is not recommended due to the architectural concerns +around MLIR depending on Clang. + +### 6.2 Scope: C Calling Convention vs. Arbitrary Calling Conventions + +This design focuses on the **C calling convention layer** (e.g. cdecl, System V, +AAPCS). C++ ABI concerns such as non-trivial copy constructors or destructors +are largely handled elsewhere in the compilation pipeline; the ABI library and +MLIR integration layer address how arguments and return values are passed at the +C ABI boundary. An open question is whether the design should remain explicitly +scoped to C calling conventions only, or be general enough to support arbitrary +calling conventions (e.g. vectorcall, preserve_most) via extensible interfaces. +Clarifying this scope will guide the design of the LLVM ABI library integration +and the MLIR pass. diff --git a/clang/docs/index.rst b/clang/docs/index.rst index 99b56e65dd3ea..0cc4bd821d1a5 100644 --- a/clang/docs/index.rst +++ b/clang/docs/index.rst @@ -127,6 +127,7 @@ Design Documents ConstantInterpreter LLVMExceptionHandlingCodeGen ClangIRCodeDuplication + ClangIRABILowering ClangIRCleanupAndEHDesign Indices and tables _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
