Skip to main content

lamina_codegen/x86_64/
mod.rs

1//! x86_64 codegen utilities
2//!
3//! This module provides register allocation, ABI handling, and frame management
4//! utilities for x86_64 code generation.
5
6pub mod abi;
7pub mod constants;
8pub mod frame;
9pub mod regalloc;
10
11pub use abi::X86ABI;
12pub use frame::X86Frame;
13pub use regalloc::X64RegAlloc;
14
15use std::io::{self, Write};
16
17/// Extend low integer bits to the full register width.
18pub fn extend_integer(
19    writer: &mut impl Write,
20    register: &str,
21    size: usize,
22    signed: bool,
23) -> io::Result<()> {
24    if size >= 8 {
25        return Ok(());
26    }
27    let source = register_for_size(register, size)
28        .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "invalid integer register"))?;
29    let (instruction, destination) = if signed {
30        (
31            match size {
32                1 => "movsbq",
33                2 => "movswq",
34                _ => "movslq",
35            },
36            register.to_string(),
37        )
38    } else {
39        (
40            match size {
41                1 => "movzbl",
42                2 => "movzwl",
43                _ => "movl",
44            },
45            register_for_size(register, 4).ok_or_else(|| {
46                io::Error::new(io::ErrorKind::InvalidInput, "invalid integer register")
47            })?,
48        )
49    };
50    writeln!(writer, "    {instruction} %{source}, %{destination}")
51}
52
53pub fn register_for_size(register: &str, size: usize) -> Option<String> {
54    let alias = match (register, size) {
55        ("rax", 1) => "al".to_string(),
56        ("rax", 2) => "ax".to_string(),
57        ("rax", 4) => "eax".to_string(),
58        ("rbx", 1) => "bl".to_string(),
59        ("rbx", 2) => "bx".to_string(),
60        ("rbx", 4) => "ebx".to_string(),
61        ("rcx", 1) => "cl".to_string(),
62        ("rcx", 2) => "cx".to_string(),
63        ("rcx", 4) => "ecx".to_string(),
64        ("rdx", 1) => "dl".to_string(),
65        ("rdx", 2) => "dx".to_string(),
66        ("rdx", 4) => "edx".to_string(),
67        ("rsi", 1) => "sil".to_string(),
68        ("rsi", 2) => "si".to_string(),
69        ("rsi", 4) => "esi".to_string(),
70        ("rdi", 1) => "dil".to_string(),
71        ("rdi", 2) => "di".to_string(),
72        ("rdi", 4) => "edi".to_string(),
73        ("rbp", 1) => "bpl".to_string(),
74        ("rbp", 2) => "bp".to_string(),
75        ("rbp", 4) => "ebp".to_string(),
76        ("rsp", 1) => "spl".to_string(),
77        ("rsp", 2) => "sp".to_string(),
78        ("rsp", 4) => "esp".to_string(),
79        (name, 1)
80            if matches!(
81                name,
82                "r8" | "r9" | "r10" | "r11" | "r12" | "r13" | "r14" | "r15"
83            ) =>
84        {
85            format!("{name}b")
86        }
87        (name, 2)
88            if matches!(
89                name,
90                "r8" | "r9" | "r10" | "r11" | "r12" | "r13" | "r14" | "r15"
91            ) =>
92        {
93            format!("{name}w")
94        }
95        (name, 4)
96            if matches!(
97                name,
98                "r8" | "r9" | "r10" | "r11" | "r12" | "r13" | "r14" | "r15"
99            ) =>
100        {
101            format!("{name}d")
102        }
103        (name, 8) => name.to_string(),
104        _ => return None,
105    };
106    Some(alias)
107}