================ @@ -0,0 +1,1617 @@ +# ClangIR ABI Lowering - Design Document + +**Version**: 1.0 +**Date**: January 2026 +**Authors**: Adam Smith (CIR Team) +**Status**: Complete Specification - Ready for Implementation +**Target**: x86_64 and AArch64 (primary), extensible to other targets + +--- + +## Quick Start: How to Read This Document + +**If you have 5 minutes**: Read Section I (Executive Summary) +**If you have 30 minutes**: Read Section I (Executive Summary) + Section V (Implementation Phases) +**If you have 2 hours**: Read the entire document +**If you're implementing**: Focus on Section IV (Architecture) and Section V (Phases) +**If you're reviewing for approval**: Focus on Section X (Open Questions) and Section XI (Success Metrics) +**If you're new to MLIR**: Read Section II (Background) first + +--- + +## Document Purpose + +This document proposes a comprehensive design for creating an MLIR-agnostic calling convention lowering framework. The framework will: +1. Enable CIR to perform ABI-compliant calling convention lowering +2. Be reusable by other MLIR dialects (FIR, future dialects) +3. Achieve parity with CIR incubator implementation for x86_64 and AArch64 +4. Integrate with or inform the GSoC ABI Lowering Library project + +## I. Executive Summary + +### 1.1 Problem Statement + +Calling convention lowering is currently implemented separately for each MLIR dialect that needs it. The CIR incubator has a partial implementation, but it's tightly coupled to CIR-specific types and operations, making it unsuitable for reuse by other dialects. This means that FIR (Fortran IR) and future MLIR dialects would need to duplicate this complex logic. While classic Clang codegen contains mature ABI lowering code, it cannot be reused directly because it's tightly coupled to Clang's AST representation and LLVM IR generation. + +### 1.2 Proposed Solution + +This design proposes a three-layer architecture that separates concerns and enables code reuse. The first layer contains pure ABI classification logic that is completely dialect-agnostic, operating only on abstract type representations. The second layer provides interface-based abstractions for querying type properties and layout information, allowing the classification logic to work with any dialect's types. The third layer handles dialect-specific operation rewriting, where each dialect implements its own operation creation logic while reusing the classification results from the lower layers. + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ MLIR-Agnostic ABI Lowering │ +│ (Three-Layer Design) │ +└─────────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────────┐ +│ Layer 3: Dialect-Specific Operation Rewriting │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ CIR Rewrite │ │ FIR Rewrite │ │ Other │ │ +│ │ Context │ │ Context │ │ Dialects │ │ +│ └──────┬──────┘ └───────┬─────┘ └────────┬────┘ │ +│ │ │ │ │ +│ └─────────────────┼─────────────────┘ │ +│ │ │ +└───────────────────────────┼─────────────────────────────────────────┘ + │ ABIRewriteContext Interface +┌───────────────────────────┼─────────────────────────────────────────┐ +│ Layer 2: Interface-Based Type Abstractions │ +│ │ │ +│ ┌────────────────────────▼──────────────────────────┐ │ +│ │ ABITypeInterface (TypeInterface) │ │ +│ │ - isRecord(), isInteger(), isFloatingPoint() │ │ +│ │ - getNumFields(), getFieldType() │ │ +│ │ - getAlignof(), getSizeof() │ │ +│ └────────────────────────┬──────────────────────────┘ │ +│ │ │ +└───────────────────────────┼─────────────────────────────────────────┘ + │ Abstract Type Queries +┌───────────────────────────┼─────────────────────────────────────────┐ +│ Layer 1: Pure ABI Classification Logic (Dialect-Agnostic) │ +│ │ │ +│ ┌────────────────────────▼──────────────────────────┐ │ +│ │ ABIInfo (Target-Specific) │ │ +│ │ - classifyArgumentType() │ │ +│ │ - classifyReturnType() │ │ +│ └──────┬─────────────────────────┬──────────────┬───┘ │ +│ │ │ │ │ +│ ┌──────▼──────┐ ┌───────────────▼───┐ ┌───────▼──────┐ │ +│ │ X86_64 │ │ AArch64 │ │ Other │ │ +│ │ ABIInfo │ │ ABIInfo │ │ Targets │ │ +│ └─────────────┘ └───────────────────┘ └──────────────┘ │ +│ │ +│ Output: LowerFunctionInfo + ABIArgInfo │ +└─────────────────────────────────────────────────────────────────────┘ + +``` + +### 1.3 Key Benefits + +This architecture avoids duplicating complex ABI logic across MLIR dialects, reducing the maintenance burden and risk of inconsistencies. It maintains correct ABI compliance for all targets by reusing proven classification algorithms. The clear separation of concerns enables easier testing and validation, as each layer can be tested independently. Additionally, the design provides a straightforward migration path from the existing CIR incubator implementation. + +### 1.4 Success Criteria + +The framework will be considered successful when CIR can correctly lower x86_64 and AArch64 calling conventions with full ABI compliance. FIR should be able to adopt the same infrastructure with minimal dialect-specific adaptation. A comprehensive test suite must validate ABI compliance across all supported targets. Finally, the performance overhead should remain under 5% compared to a direct, dialect-specific implementation. + +## 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 +``` + +### 2.2 Why It's Complex + +Calling convention lowering is complex for several reasons. First, it's highly target-specific: each architecture (x86_64, AArch64, RISC-V, etc.) has different rules for how arguments are passed in registers versus memory. Second, it's type-dependent: the rules differ significantly for integers, floating-point values, structs, unions, and arrays. Third, it's context-sensitive: special handling is required for varargs functions, virtual method calls, and alternative calling conventions like vectorcall or preserve_most. Finally, the same target may have multiple ABI variants (e.g., x86_64 System V vs. Windows x64), adding another dimension of complexity. + +### 2.3 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 difficult 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 codegen to work within the MLIR framework. However, it relies on CIR-specific types and operations, preventing reuse by other MLIR dialects. + +#### GSoC ABI Lowering Library (WIP) + +The Google Summer of Code project (PR #140112, not yet merged) proposes an independent ABI type system extracted from Clang's codegen. This library aims to be frontend-agnostic and reusable across different language frontends. While promising, it's still under development and currently focuses on Clang and LLVM IR rather than MLIR abstractions. ---------------- nikic wrote:
I think you need to provide a really good justification why you need something other than the LLVM ABI lowering library, other than "it's not upstreamed yet". Having another abstraction around it on the MLIR level would be fine, but the core ABI logic should live in one place and one place only (which is the LLVM ABI library). https://github.com/llvm/llvm-project/pull/178326 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
