Skip to content

feat: implement System V ABI-compliant C FFI lowering#283

Merged
LunaStev merged 1 commit into
wavefnd:masterfrom
LunaStev:feat/implement-System-V-ABI-compliant-C-FFI-lowering
Feb 6, 2026
Merged

feat: implement System V ABI-compliant C FFI lowering#283
LunaStev merged 1 commit into
wavefnd:masterfrom
LunaStev:feat/implement-System-V-ABI-compliant-C-FFI-lowering

Conversation

@LunaStev
Copy link
Copy Markdown
Member

@LunaStev LunaStev commented Feb 6, 2026

This PR introduces a robust C calling convention (ABI) lowering layer to the Wave compiler's LLVM backend. Until now, calling external C functions was limited to simple types. This update allows Wave to interface with complex C APIs that involve passing or returning structures and arrays by value, strictly adhering to the System V ABI (x86_64) standards.

Key Changes

1. ABI Lowering Logic (abi_c.rs)

Implemented a new lowering engine to classify how Wave types should be translated for the C ABI:

  • SRet (Structured Return): Handles large return types by automatically inserting a hidden first parameter that points to a caller-allocated memory block.
  • ByVal (By Value): Implements the ByVal attribute for structures, ensuring they are passed on the stack or in registers with correct alignment as expected by C.
  • Split & HFA (Homogeneous Floating-point Aggregate): Implements logic to decompose small structs into multiple registers (integer or floating-point/SSE), allowing for efficient "register-splitting" of aggregates.
  • Direct & Bit-Packing: Small structures are now "packed" into a single integer register (pack_agg_to_int) when possible, matching the standard optimization behavior of C compilers.

2. Backend Infrastructure & Metadata

  • Target-Aware Codegen: The backend now initializes and propagates LLVM TargetData and TargetMachine. This ensures the compiler has precise information about the host's size and alignment requirements.
  • ExternCInfo: Introduced a metadata container to track lowered function signatures, ensuring that the calling site (at the LLVM level) matches the ABI transformations applied to the declaration.
  • Context Propagation: Propagated TargetData and ABI info through all major generators, including gen_function_call and generate_lvalue_ir.

3. Refactored Function Calls

  • Call-site Transformation: The gen_function_call logic has been refactored to check if a target is an extern(c) function. If so, it applies the necessary transformations:
    • Casting arguments to the lowered ABI types.
    • Unpacking split registers back into a single Wave struct.
    • Managing SRet pointers for functions that return large aggregates.

4. Maintenance

  • Removed several unused variables and refined internal type inference logic in the parser to accommodate the stricter backend requirements.

Example Impact

Previously, passing a struct like struct Vec2 { x: f32, y: f32 } to a C function might fail if the ABI expected them in a single SSE register. Now, Wave correctly identifies this as an HFA and emits the proper IR to match C's expected register layout.

Benefits

  • Full FFI Compatibility: Wave can now reliably invoke any C library function, including those that use complex struct passing (e.g., stat, ioctl, or high-performance math libraries).
  • Performance: Register-based aggregate passing is significantly faster than always falling back to stack-based pointers.
  • Safety: Stricter alignment and size tracking prevents buffer overflows and memory corruption during FFI boundaries.

This commit introduces a robust C calling convention (ABI) lowering
mechanism to the LLVM backend. It allows Wave to interface with external
C functions by correctly handling complex data types (structs and arrays)
according to standard ABI rules, such as SRet, ByVal, and register splitting.

Changes:
- **ABI Lowering Logic (`abi_c.rs`)**:
  - Implemented `ParamLowering` and `RetLowering` to classify how types
    should be passed (Direct, Split, ByVal, or SRet).
  - Added support for **SRet** (Structured Return) to handle large
    aggregates via a hidden first parameter.
  - Added support for **ByVal** attributes to pass structures by value
    with proper ABI alignment.
  - Implemented **Split/HFA (Homogeneous Floating-point Aggregate)**
    logic to pass small aggregates using multiple floating-point or
    vector registers.
- **Backend Infrastructure**:
  - Updated the codegen pipeline to initialize and propagate `TargetData`
    and `TargetMachine`, enabling accurate size and alignment calculations.
  - Introduced `ExternCInfo` to store lowered function metadata and
    propagated it through all expression and statement generators.
  - Added bit-packing (`pack_agg_to_int`) and unpacking utilities to
    facilitate passing small structs via integer registers.
- **Expression & Statement Generators**:
  - Refactored `gen_function_call` to check for extern C signatures and
    apply necessary ABI transformations (e.g., bit-casting, loading
    from SRet pointers, or splitting HFAs).
  - Propagated `TargetData` to `generate_lvalue_ir` and other generators
    to support context-aware codegen.
- **Cleanup**:
  - Removed unused variables and refined internal type inference logic
    in the parser and codegen.

These changes ensure that Wave can safely and efficiently invoke
external C libraries, handling complex signatures that involve
passing or returning structures by value.

Signed-off-by: LunaStev <luna@lunastev.org>
@LunaStev LunaStev merged commit 14c4c11 into wavefnd:master Feb 6, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant