Skip to content

Inline Assembly #248

@tahadostifam

Description

@tahadostifam

Language Feature Proposal: Inline Assembly

Overview

This proposal extends the Cyrus language with inline assembly support, allowing developers to write platform-specific assembly code directly within Cyrus programs. The design follows a built-in function approach similar to other low-level operations, providing type safety and integration with the Cyrus type system.

Syntax

Basic Inline Assembly

// Basic form
@asm("assembly template" : outputs : inputs : clobbers);

// With constraints
@asm("mov %0, %1" : "=r"(result) : "r"(input) : "cc");

Extended Form for Multiple Instructions

@asm {
    "assembly line 1\n"
    "assembly line 2\n"
    ...
} : outputs : inputs : clobbers;

Design

Core Function Signature

// Pseudo-signature
fn @asm(
    comptime template: []const u8,
    outputs: ...,
    inputs: ...,
    clobbers: ...,
    options: AsmOptions
) -> ReturnType;

Return Type Inference

The return type is inferred from the outputs:

  • No outputs → void
  • Single output → Type of that output
  • Multiple outputs → Tuple of output types

Constraint Modifiers

Common Constraints

Constraint Description Example
r Any general-purpose register "r"(value)
m Memory operand "m"(ptr)
i Immediate integer "i"(42)
g Any register, memory, or immediate "g"(expr)
=r Write-only output register "=r"(result)
+r Read-write operand "+r"(counter)
&r Early-clobber register "=&r"(temp)

Architecture-specific Constraints

// x86/x86-64 specific
@asm("rdtsc" : "={eax}"(low), "={edx}"(high) : : "eax", "edx");

// ARM/AArch64 specific
@asm("mrs %0, cntvct_el0" : "=r"(timer) : : );

Examples

Basic Operations

// Read CPU timestamp counter on x86
fn rdtsc() -> u64 {
    var low: u32;
    var high: u32;
    
    @asm("rdtsc" 
        : "={eax}"(low), "={edx}"(high) 
        : 
        : "eax", "edx"
    );
    
    return (@cast(u64, high) << 32) | @cast(u64, low);
}

// System call on x86-64 Linux
fn syscall1(number: i64, arg1: i64) -> i64 {
    var result: i64;
    
    @asm("syscall"
        : "={rax}"(result)
        : "{rax}"(number), "{rdi}"(arg1)
        : "rcx", "r11", "memory"
    );
    
    return result;
}

Memory Operations

// Atomic compare-and-swap
fn cmpxchg(ptr: *mut u32, expected: u32, desired: u32) -> (u32, bool) {
    var prev: u32 = expected;
    var zero: u32;
    
    @asm("lock cmpxchg %2, %1"
        : "={eax}"(prev), "=m"(*ptr), "=@ccz"(zero)
        : "{eax}"(expected), "m"(*ptr), "r"(desired)
        : "memory"
    );
    
    return (prev, zero != 0);
}

// Memory barrier
fn memory_barrier() {
    @asm("mfence" : : : "memory");
}

Architecture Detection

// Architecture-specific implementations
fn pause_cpu() {
    const target = @env().target;
        
    switch (target.cpu.arch) {
        case .X86, .X86_64 => {
            @asm("pause" : : : );
        },
        case .Arm, .AArch64 => {
            @asm("yield" : : : );
        },
        default => {
            // Generic memory barrier as fallback
            @asm("" : : : "memory");
        }
    }
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

New Phase

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions