Inferensys

Glossary

Calling Convention

A calling convention is a low-level protocol that defines how functions receive parameters, return values, and manage registers and the stack during a subroutine call, ensuring binary compatibility.
Stylish WeWork-like workspace with hot desks and document wall, professional searching through enterprise knowledge base on a mounted ultrawide display, warm industrial pendants overhead.
LOW-LEVEL PROTOCOL

What is a Calling Convention?

A foundational protocol in systems programming that governs how functions are called and return in compiled code.

A calling convention is a low-level protocol that defines how functions receive parameters, return values, and manage CPU registers and the call stack during a subroutine call. It specifies the order in which arguments are passed (e.g., left-to-right or right-to-left), which party—the caller or callee—is responsible for cleaning the stack, and which registers must be preserved across the call. This protocol is essential for ensuring binary compatibility between modules compiled separately, such as an application and a vendor's NPU runtime library.

In the context of NPU acceleration, calling conventions are critical when linking code compiled for the host CPU with functions implemented in a vendor SDK or hardware intrinsics library targeting the accelerator. Mismatched conventions cause catastrophic runtime failures. Common examples include the cdecl, stdcall, and fastcall conventions on x86, and the AAPCS (ARM Architecture Procedure Call Standard) on ARM platforms. Compilers and linkers use this agreed-upon contract to generate correct machine code for function prologues and epilogues.

Vendor SDK and Intrinsic Mapping

Key Components of a Calling Convention

A calling convention is a foundational low-level protocol that dictates the precise mechanics of function invocation. It ensures binary compatibility between modules compiled by different tools or for different hardware targets, which is critical for linking vendor libraries with custom code on NPUs.

01

Parameter Passing

Defines how arguments are transferred from the caller to the callee. This specifies:

  • Register-based passing: Fast, using designated general-purpose or special-purpose registers (e.g., R0-R3 on ARM).
  • Stack-based passing: For excess arguments or large data structures, pushed onto the call stack in a defined order (left-to-right or right-to-left).
  • Composite types: Rules for passing structs or vectors, which may be split across registers, passed by reference, or copied to the stack.
  • Example: The ARM Procedure Call Standard (AAPCS) uses R0-R3 for the first four integer/pointer arguments, with subsequent arguments passed on the stack.
02

Register Usage & Preservation

Governs which CPU/NPU registers are volatile (caller-saved) and which are non-volatile (callee-saved). This is essential for preventing unintended side-effects.

  • Volatile Registers: Can be overwritten by a called function. The caller must save any important values before the call. Used for scratch computation and return values.
  • Non-Volatile Registers: Must be preserved by the callee. If used, the callee must save their original values to the stack and restore them before returning.
  • Implications: Incorrect register preservation leads to subtle, hard-to-debug corruption. Vendor intrinsics and runtime libraries adhere strictly to the target's convention.
03

Stack Frame Management

Specifies the layout and responsibilities for managing the call stack during a function's lifetime.

  • Stack Pointer (SP) Alignment: Often requires alignment to a specific boundary (e.g., 16 bytes) for performance and hardware requirements.
  • Frame Pointer (FP): An optional register (e.g., R29 on ARM, RBP on x86) that points to a stable location within the current stack frame, aiding debugging and stack unwinding.
  • Prologue/Epilogue: The sequence of instructions at the start and end of a function that allocates/deallocates stack space, saves/restores registers, and sets up/tears down the frame pointer.
  • Local Variables: Space for automatic (local) variables is allocated on the stack within the function's frame.
04

Return Value Handling

Defines how a function returns its result to the caller.

  • Simple Scalars: Typically returned in a designated register (e.g., R0 on ARM, RAX on x86-64).
  • Floating-Point/SIMD Values: Returned in specific vector registers (e.g., S0/D0 on ARM, XMM0 on x86).
  • Large Values: Structs or vectors too large for registers are handled via hidden pointer: the caller allocates memory and passes its address as an implicit first argument; the callee writes the result there.
  • Multiple Return Values: Some conventions (or language extensions) support returning multiple values via a combination of registers and the hidden pointer method.
05

Caller vs. Callee Cleanup

Determines which party is responsible for removing arguments from the stack after the call, a critical distinction for variadic functions and code size.

  • Callee-cleanup (e.g., stdcall): The called function pops its own arguments. This often leads to smaller code in the caller but cannot support variadic functions like printf.
  • Caller-cleanup (e.g., cdecl): The caller removes the arguments after the call returns. This supports variadic functions and allows for cleaner stack management in the callee but increases caller code size.
  • Impact on NPUs: Vendor SDKs dictate a specific model. Mixing conventions when linking custom assembly with C/C++ code will cause catastrophic stack corruption.
06

System vs. Hardware Conventions

Highlights the distinction between conventions for different execution environments on the same chip.

  • System (CPU) Calling Convention: Governs function calls on the host CPU (e.g., ARM AAPCS, x86-64 System V ABI). Used for control code and invoking the NPU driver.
  • Hardware (NPU) Calling Convention: A vendor-specific protocol for invoking kernels or microcode on the accelerator itself. This defines:
    • How kernel arguments are packed and passed via command buffers.
    • The register state of the NPU's tensor/vector cores upon kernel entry/exit.
    • Management of the NPU's internal scratchpad memory or local data RAM (LDRAM).
  • Interaction: The CPU uses its convention to call the Vendor Runtime API, which then formats commands adhering to the NPU's internal convention.
CALLING CONVENTION

Role in NPU Acceleration and Vendor SDKs

A calling convention is a low-level protocol that defines how functions receive parameters, return values, and manage registers and the stack during a subroutine call, ensuring binary compatibility between different modules.

In NPU acceleration, the calling convention is a critical contract between the host CPU and the accelerator's execution units. It dictates how kernel arguments—such as tensor pointers, dimensions, and scalar parameters—are passed from the host driver to the NPU's specialized cores. This protocol is strictly defined by the vendor's Instruction Set Architecture (ISA) and enforced by its compiler toolchain and runtime libraries. Adherence guarantees that compiled kernels execute correctly on the target hardware, managing the handoff of control and data across the heterogeneous system.

Vendor SDKs and hardware abstraction layers (HALs) implement this convention, providing the Application Binary Interface (ABI) that bridges high-level frameworks and low-level hardware. Developers typically interact with it indirectly through compiler intrinsics or driver APIs. The convention governs register allocation, stack frame management, and parameter passing order for NPU kernels, which is essential for binary portability and the correct functioning of statically linked libraries within the accelerator's execution environment.

LOW-LEVEL PROTOCOLS

Common Calling Conventions: A Comparison

This table compares the key characteristics of prevalent calling conventions used in system-level programming, particularly relevant for interfacing with vendor SDKs and hardware intrinsics.

Feature / Rulecdecl (C Declaration)stdcall (Standard Call)fastcallSystem V AMD64 ABI

Primary Use Case

C language default (x86)

Microsoft Win32 API

Performance-critical x86 code

Default for x86-64 on Linux, macOS

Caller/Callee Stack Cleanup

Caller

Callee

Callee

Caller (for variable arguments)

Integer/Pointer Parameter Passing (First 2-6 args)

Stack only

Stack only

Registers (ECX, EDX), then stack

Registers (RDI, RSI, RDX, RCX, R8, R9), then stack

Floating-Point Parameter Passing (x86-64)

N/A (x86 stack)

N/A (x86 stack)

N/A

XMM0–XMM7 registers, then stack

Return Value (Integer/Pointer)

EAX register

EAX register

EAX register

RAX register

Return Value (Floating-Point)

ST0 (x87 FPU stack)

ST0 (x87 FPU stack)

ST0 (x87 FPU stack)

XMM0 register

Registers Preserved (Callee-saved)

EBX, ESI, EDI, EBP, ESP

EBX, ESI, EDI, EBP, ESP

EBX, ESI, EDI, EBP, ESP

RBX, RBP, R12-R15

Name Mangling (C++)

Underscore prefix (varies)

Decorated with argument size

Decorated with '@' and size

Complex mangling (Itanium C++ ABI)

Variable Argument Support (e.g., printf)

CALLING CONVENTION

Frequently Asked Questions

A calling convention is a critical low-level protocol that defines how functions are called in compiled code. It ensures binary compatibility between modules by standardizing parameter passing, register usage, stack management, and return value handling.

A calling convention is a low-level protocol that defines how a function (a subroutine or procedure) receives its parameters, returns its result, and manages CPU registers and the stack memory during a call. It is a contract between the caller (the code making the function call) and the callee (the function being called) that ensures they agree on where to find arguments, which registers must be preserved, and how to clean up the stack after the call. This protocol is essential for binary compatibility, allowing code compiled by different compilers or at different times to interoperate correctly. For NPU programming, calling conventions are crucial when interfacing hand-optimized kernels written in assembly or with hardware intrinsics with higher-level code generated by a compiler.

Prasad Kumkar

About the author

Prasad Kumkar

CEO & MD, Inference Systems

Prasad Kumkar is the CEO & MD of Inference Systems and writes about AI systems architecture, LLM infrastructure, model serving, evaluation, and production deployment. Over 5+ years, he has worked across computer vision models, L5 autonomous vehicle systems, and LLM research, with a focus on taking complex AI ideas into real-world engineering systems.

His work and writing cover AI systems, large language models, AI agents, multimodal systems, autonomous systems, inference optimization, RAG, evaluation, and production AI engineering.