qbe/
lib.rs

1// Copyright 2022 Garrit Franke
2// Copyright 2021 Alexey Yerin
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10//! # QBE Rust
11//!
12//! A Rust library for programmatically generating QBE Intermediate Language code.
13//!
14//! [QBE](https://c9x.me/compile/) is a compiler backend that transforms simple intermediate
15//! representation (IR) into executable machine code. This library provides Rust data structures
16//! and functions to generate valid QBE IL.
17//!
18//! ## Basic Example
19//!
20//! ```rust
21//! use qbe::{Module, Function, Linkage, Type, Value, Instr};
22//!
23//! // Create a new module
24//! let mut module = Module::new();
25//!
26//! // Add a simple function that returns the sum of two integers
27//! let mut func = Function::new(
28//!     Linkage::public(),
29//!     "add",
30//!     vec![
31//!         (Type::Word, Value::Temporary("a".to_string())),
32//!         (Type::Word, Value::Temporary("b".to_string())),
33//!     ],
34//!     Some(Type::Word),
35//! );
36//!
37//! // Add a block to the function
38//! let mut block = func.add_block("start");
39//!
40//! // Add two arguments and store result in "sum"
41//! block.assign_instr(
42//!     Value::Temporary("sum".to_string()),
43//!     Type::Word,
44//!     Instr::Add(
45//!         Value::Temporary("a".to_string()),
46//!         Value::Temporary("b".to_string()),
47//!     ),
48//! );
49//!
50//! // Return the sum
51//! block.add_instr(Instr::Ret(Some(Value::Temporary("sum".to_string()))));
52//!
53//! // Add the function to the module
54//! module.add_function(func);
55//!
56//! // Generate QBE IL code
57//! println!("{}", module);
58//! ```
59//!
60//! This generates the following QBE IL:
61//! ```ssa
62//! export function w $add(w %a, w %b) {
63//! @start
64//!     %sum =w add %a, %b
65//!     ret %sum
66//! }
67//! ```
68
69use std::fmt;
70
71#[cfg(test)]
72mod tests;
73
74/// QBE comparison operations used in conditional instructions.
75///
76/// The result of a comparison is 1 if the condition is true, and 0 if false.
77///
78/// # Examples
79///
80/// ```rust
81/// use qbe::{Cmp, Instr, Type, Value};
82///
83/// // Compare if %a is less than %b (signed comparison)
84/// let slt_instr = Instr::Cmp(
85///     Type::Word,
86///     Cmp::Slt,
87///     Value::Temporary("a".to_string()),
88///     Value::Temporary("b".to_string()),
89/// );
90///
91/// // Check if two values are equal
92/// let eq_instr = Instr::Cmp(
93///     Type::Word,
94///     Cmp::Eq,
95///     Value::Temporary("x".to_string()),
96///     Value::Const(0),
97/// );
98/// ```
99#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Copy)]
100pub enum Cmp {
101    /// Returns 1 if first value is less than second, respecting signedness
102    Slt,
103    /// Returns 1 if first value is less than or equal to second, respecting signedness
104    Sle,
105    /// Returns 1 if first value is greater than second, respecting signedness
106    Sgt,
107    /// Returns 1 if first value is greater than or equal to second, respecting signedness
108    Sge,
109    /// Returns 1 if values are equal
110    Eq,
111    /// Returns 1 if values are not equal
112    Ne,
113    /// Returns 1 if both operands are not NaN (ordered comparison)
114    O,
115    /// Returns 1 if at least one operand is NaN (unordered comparison)
116    Uo,
117    /// Returns 1 if first value is less than second, unsigned comparison
118    Ult,
119    /// Returns 1 if first value is less than or equal to second, unsigned comparison
120    Ule,
121    /// Returns 1 if first value is greater than second, unsigned comparison
122    Ugt,
123    /// Returns 1 if first value is greater than or equal to second, unsigned comparison
124    Uge,
125}
126
127/// QBE instructions representing operations in the intermediate language.
128///
129/// # Examples
130///
131/// ## Arithmetic Operations
132/// ```rust
133/// use qbe::{Instr, Value};
134///
135/// // Addition: %result = %a + %b
136/// let add = Instr::Add(
137///     Value::Temporary("a".to_string()),
138///     Value::Temporary("b".to_string()),
139/// );
140///
141/// // Multiplication: %result = %x * 5
142/// let mul = Instr::Mul(
143///     Value::Temporary("x".to_string()),
144///     Value::Const(5),
145/// );
146/// ```
147///
148/// ## Memory Operations
149/// ```rust
150/// use qbe::{Instr, Type, Value};
151///
152/// // Allocate 8 bytes on the stack with 8-byte alignment
153/// let alloc = Instr::Alloc8(8);
154///
155/// // Store a word to memory: store %value, %ptr
156/// let store = Instr::Store(
157///     Type::Word,
158///     Value::Temporary("ptr".to_string()),
159///     Value::Temporary("value".to_string()),
160/// );
161///
162/// // Load a word from memory: %result = load %ptr
163/// let load = Instr::Load(
164///     Type::Word,
165///     Value::Temporary("ptr".to_string()),
166/// );
167/// ```
168///
169/// ## Control Flow
170/// ```rust
171/// use qbe::{Instr, Value};
172///
173/// // Conditional jump based on %condition
174/// let branch = Instr::Jnz(
175///     Value::Temporary("condition".to_string()),
176///     "true_branch".to_string(),
177///     "false_branch".to_string(),
178/// );
179///
180/// // Return a value from a function
181/// let ret = Instr::Ret(Some(Value::Temporary("result".to_string())));
182/// ```
183#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
184pub enum Instr<'a> {
185    /// Adds values of two temporaries together
186    Add(Value, Value),
187    /// Subtracts the second value from the first one
188    Sub(Value, Value),
189    /// Multiplies values of two temporaries
190    Mul(Value, Value),
191    /// Divides the first value by the second one
192    Div(Value, Value),
193    /// Returns a remainder from division
194    Rem(Value, Value),
195    /// Performs a comparion between values
196    Cmp(Type<'a>, Cmp, Value, Value),
197    /// Performs a bitwise AND on values
198    And(Value, Value),
199    /// Performs a bitwise OR on values
200    Or(Value, Value),
201    /// Copies either a temporary or a literal value
202    Copy(Value),
203    /// Return from a function, optionally with a value
204    Ret(Option<Value>),
205    /// Jumps to first label if a value is nonzero or to the second one otherwise
206    Jnz(Value, String, String),
207    /// Unconditionally jumps to a label
208    Jmp(String),
209    /// Calls a function
210    Call(String, Vec<(Type<'a>, Value)>, Option<u64>),
211    /// Allocates a 4-byte aligned area on the stack
212    Alloc4(u32),
213    /// Allocates a 8-byte aligned area on the stack
214    Alloc8(u64),
215    /// Allocates a 16-byte aligned area on the stack
216    Alloc16(u128),
217    /// Stores a value into memory pointed to by destination.
218    /// `(type, destination, value)`
219    Store(Type<'a>, Value, Value),
220    /// Loads a value from memory pointed to by source
221    /// `(type, source)`
222    Load(Type<'a>, Value),
223    /// `(source, destination, n)`
224    ///
225    /// Copy `n` bytes from the source address to the destination address.
226    ///
227    /// n must be a constant value.
228    ///
229    /// ## Minimum supported QBE version
230    /// `1.1`
231    Blit(Value, Value, u64),
232
233    /// Debug file.
234    DbgFile(String),
235    /// Debug line.
236    ///
237    /// Takes line number and an optional column.
238    DbgLoc(u64, Option<u64>),
239
240    // Unsigned arithmetic
241    /// Performs unsigned division of the first value by the second one
242    Udiv(Value, Value),
243    /// Returns the remainder from unsigned division
244    Urem(Value, Value),
245
246    // Shifts
247    /// Shift arithmetic right (preserves sign)
248    Sar(Value, Value),
249    /// Shift logical right (fills with zeros)
250    Shr(Value, Value),
251    /// Shift left (fills with zeros)
252    Shl(Value, Value),
253
254    // Type conversions
255    /// Cast between integer and floating point of the same width
256    Cast(Value),
257
258    // Extension operations
259    /// Sign-extends a word to a long
260    Extsw(Value),
261    /// Zero-extends a word to a long
262    Extuw(Value),
263    /// Sign-extends a halfword to a word or long
264    Extsh(Value),
265    /// Zero-extends a halfword to a word or long
266    Extuh(Value),
267    /// Sign-extends a byte to a word or long
268    Extsb(Value),
269    /// Zero-extends a byte to a word or long
270    Extub(Value),
271    /// Extends a single-precision float to double-precision
272    Exts(Value),
273    /// Truncates a double-precision float to single-precision
274    Truncd(Value),
275
276    // Float-integer conversions
277    /// Converts a single-precision float to a signed integer
278    Stosi(Value),
279    /// Converts a single-precision float to an unsigned integer
280    Stoui(Value),
281    /// Converts a double-precision float to a signed integer
282    Dtosi(Value),
283    /// Converts a double-precision float to an unsigned integer
284    Dtoui(Value),
285    /// Converts a signed word to a float
286    Swtof(Value),
287    /// Converts an unsigned word to a float
288    Uwtof(Value),
289    /// Converts a signed long to a float
290    Sltof(Value),
291    /// Converts an unsigned long to a float
292    Ultof(Value),
293
294    // Variadic function support
295    /// Initializes a variable argument list
296    Vastart(Value),
297    /// Fetches the next argument from a variable argument list
298    Vaarg(Type<'a>, Value),
299
300    // Phi instruction
301    /// Selects value based on the control flow path into a block.
302    Phi(String, Value, String, Value),
303
304    // Program termination
305    /// Terminates the program with an error
306    Hlt,
307}
308
309impl fmt::Display for Instr<'_> {
310    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
311        match self {
312            Self::Add(lhs, rhs) => write!(f, "add {lhs}, {rhs}"),
313            Self::Sub(lhs, rhs) => write!(f, "sub {lhs}, {rhs}"),
314            Self::Mul(lhs, rhs) => write!(f, "mul {lhs}, {rhs}"),
315            Self::Div(lhs, rhs) => write!(f, "div {lhs}, {rhs}"),
316            Self::Rem(lhs, rhs) => write!(f, "rem {lhs}, {rhs}"),
317            Self::Cmp(ty, cmp, lhs, rhs) => {
318                assert!(
319                    !matches!(ty, Type::Aggregate(_)),
320                    "Cannot compare aggregate types"
321                );
322
323                write!(
324                    f,
325                    "c{}{} {}, {}",
326                    match cmp {
327                        Cmp::Slt => "slt",
328                        Cmp::Sle => "sle",
329                        Cmp::Sgt => "sgt",
330                        Cmp::Sge => "sge",
331                        Cmp::Eq => "eq",
332                        Cmp::Ne => "ne",
333                        Cmp::O => "o",
334                        Cmp::Uo => "uo",
335                        Cmp::Ult => "ult",
336                        Cmp::Ule => "ule",
337                        Cmp::Ugt => "ugt",
338                        Cmp::Uge => "uge",
339                    },
340                    ty,
341                    lhs,
342                    rhs,
343                )
344            }
345            Self::And(lhs, rhs) => write!(f, "and {lhs}, {rhs}"),
346            Self::Or(lhs, rhs) => write!(f, "or {lhs}, {rhs}"),
347            Self::Copy(val) => write!(f, "copy {val}"),
348            Self::Ret(val) => match val {
349                Some(val) => write!(f, "ret {val}"),
350                None => write!(f, "ret"),
351            },
352            Self::DbgFile(val) => write!(f, r#"dbgfile "{val}""#),
353            Self::DbgLoc(lineno, column) => match column {
354                Some(val) => write!(f, "dbgloc {lineno}, {val}"),
355                None => write!(f, "dbgloc {lineno}"),
356            },
357            Self::Jnz(val, if_nonzero, if_zero) => {
358                write!(f, "jnz {val}, @{if_nonzero}, @{if_zero}")
359            }
360            Self::Jmp(label) => write!(f, "jmp @{label}"),
361            Self::Call(name, args, opt_variadic_i) => {
362                let mut args_fmt = args
363                    .iter()
364                    .map(|(ty, temp)| format!("{ty} {temp}"))
365                    .collect::<Vec<String>>();
366                if let Some(i) = *opt_variadic_i {
367                    args_fmt.insert(i as usize, "...".to_string());
368                }
369
370                write!(f, "call ${}({})", name, args_fmt.join(", "),)
371            }
372            Self::Alloc4(size) => write!(f, "alloc4 {size}"),
373            Self::Alloc8(size) => write!(f, "alloc8 {size}"),
374            Self::Alloc16(size) => write!(f, "alloc16 {size}"),
375            Self::Store(ty, dest, value) => {
376                if matches!(ty, Type::Aggregate(_)) {
377                    unimplemented!("Store to an aggregate type");
378                }
379
380                write!(f, "store{ty} {value}, {dest}")
381            }
382            Self::Load(ty, src) => {
383                if matches!(ty, Type::Aggregate(_)) {
384                    unimplemented!("Load aggregate type");
385                }
386
387                write!(f, "load{ty} {src}")
388            }
389            Self::Blit(src, dst, n) => write!(f, "blit {src}, {dst}, {n}"),
390            Self::Udiv(lhs, rhs) => write!(f, "udiv {lhs}, {rhs}"),
391            Self::Urem(lhs, rhs) => write!(f, "urem {lhs}, {rhs}"),
392            Self::Sar(lhs, rhs) => write!(f, "sar {lhs}, {rhs}"),
393            Self::Shr(lhs, rhs) => write!(f, "shr {lhs}, {rhs}"),
394            Self::Shl(lhs, rhs) => write!(f, "shl {lhs}, {rhs}"),
395            Self::Cast(val) => write!(f, "cast {val}"),
396            Self::Extsw(val) => write!(f, "extsw {val}"),
397            Self::Extuw(val) => write!(f, "extuw {val}"),
398            Self::Extsh(val) => write!(f, "extsh {val}"),
399            Self::Extuh(val) => write!(f, "extuh {val}"),
400            Self::Extsb(val) => write!(f, "extsb {val}"),
401            Self::Extub(val) => write!(f, "extub {val}"),
402            Self::Exts(val) => write!(f, "exts {val}"),
403            Self::Truncd(val) => write!(f, "truncd {val}"),
404            Self::Stosi(val) => write!(f, "stosi {val}"),
405            Self::Stoui(val) => write!(f, "stoui {val}"),
406            Self::Dtosi(val) => write!(f, "dtosi {val}"),
407            Self::Dtoui(val) => write!(f, "dtoui {val}"),
408            Self::Swtof(val) => write!(f, "swtof {val}"),
409            Self::Uwtof(val) => write!(f, "uwtof {val}"),
410            Self::Sltof(val) => write!(f, "sltof {val}"),
411            Self::Ultof(val) => write!(f, "ultof {val}"),
412            Self::Vastart(val) => write!(f, "vastart {val}"),
413            Self::Vaarg(ty, val) => write!(f, "vaarg{ty} {val}"),
414            Self::Phi(label_1, val_if_label_1, label_2, val_if_label_2) => {
415                write!(
416                    f,
417                    "phi @{label_1} {val_if_label_1}, @{label_2} {val_if_label_2}"
418                )
419            }
420            Self::Hlt => write!(f, "hlt"),
421        }
422    }
423}
424
425/// QBE types used to specify the size and representation of values.
426///
427/// QBE has a minimal type system with base types and extended types.
428/// Base types are used for temporaries, while extended types can be used
429/// in aggregate types and data definitions.
430///
431/// # Examples
432///
433/// ```rust
434/// use qbe::Type;
435///
436/// // Base types
437/// let word = Type::Word;     // 32-bit integer
438/// let long = Type::Long;     // 64-bit integer
439/// let single = Type::Single; // 32-bit float
440/// let double = Type::Double; // 64-bit float
441///
442/// // Extended types
443/// let byte = Type::Byte;     // 8-bit value
444/// let halfword = Type::Halfword; // 16-bit value
445///
446/// // Get type sizes in bytes
447/// assert_eq!(word.size(), 4);
448/// assert_eq!(byte.size(), 1);
449/// ```
450///
451/// ## Type Conversions
452///
453/// ```rust
454/// use qbe::Type;
455///
456/// // Convert extended type to corresponding base type
457/// let base = Type::Byte.into_base();
458/// assert_eq!(base, Type::Word);
459///
460/// // Convert to ABI-compatible type for function parameters
461/// let abi = Type::SignedByte.into_abi();
462/// assert_eq!(abi, Type::Word);
463/// ```
464#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
465pub enum Type<'a> {
466    // Base types
467    Word,
468    Long,
469    Single,
470    Double,
471
472    // Internal types
473    Zero,
474
475    // Extended types
476    Byte,
477    SignedByte,
478    UnsignedByte,
479    Halfword,
480    SignedHalfword,
481    UnsignedHalfword,
482
483    /// Aggregate type with a specified name
484    Aggregate(&'a TypeDef<'a>),
485}
486
487impl Type<'_> {
488    /// Returns a C ABI type. Extended types are converted to closest base
489    /// types
490    pub fn into_abi(self) -> Self {
491        match self {
492            Self::Byte
493            | Self::SignedByte
494            | Self::UnsignedByte
495            | Self::Halfword
496            | Self::SignedHalfword
497            | Self::UnsignedHalfword => Self::Word,
498            other => other,
499        }
500    }
501
502    /// Returns the closest base type
503    pub fn into_base(self) -> Self {
504        match self {
505            Self::Byte
506            | Self::SignedByte
507            | Self::UnsignedByte
508            | Self::Halfword
509            | Self::SignedHalfword
510            | Self::UnsignedHalfword => Self::Word,
511            Self::Aggregate(_) => Self::Long,
512            other => other,
513        }
514    }
515
516    /// Returns byte size for values of the type
517    pub fn size(&self) -> u64 {
518        match self {
519            Self::Byte | Self::SignedByte | Self::UnsignedByte | Self::Zero => 1,
520            Self::Halfword | Self::SignedHalfword | Self::UnsignedHalfword => 2,
521            Self::Word | Self::Single => 4,
522            Self::Long | Self::Double => 8,
523            Self::Aggregate(td) => {
524                let mut offset = 0;
525
526                // calculation taken from: https://en.wikipedia.org/wiki/Data_structure_alignment#Computing%20padding
527                for (item, repeat) in td.items.iter() {
528                    let align = item.align();
529                    let size = *repeat as u64 * item.size();
530                    let padding = (align - (offset % align)) % align;
531                    offset += padding + size;
532                }
533
534                let align = self.align();
535                let padding = (align - (offset % align)) % align;
536
537                // size is the final offset with the padding that is left
538                offset + padding
539            }
540        }
541    }
542
543    /// Returns byte alignment for values of the type
544    pub fn align(&self) -> u64 {
545        match self {
546            Self::Aggregate(td) => {
547                if let Some(align) = td.align {
548                    return align;
549                }
550
551                // the alignment of a type is the maximum alignment of its members
552                // when there's no members, the alignment is usuallly defined to be 1.
553                td.items
554                    .iter()
555                    .map(|item| item.0.align())
556                    .max()
557                    .unwrap_or(1)
558            }
559
560            _ => self.size(),
561        }
562    }
563}
564
565impl fmt::Display for Type<'_> {
566    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
567        match self {
568            Self::Byte => write!(f, "b"),
569            Self::SignedByte => write!(f, "sb"),
570            Self::UnsignedByte => write!(f, "ub"),
571            Self::Halfword => write!(f, "h"),
572            Self::SignedHalfword => write!(f, "sh"),
573            Self::UnsignedHalfword => write!(f, "uh"),
574            Self::Word => write!(f, "w"),
575            Self::Long => write!(f, "l"),
576            Self::Single => write!(f, "s"),
577            Self::Double => write!(f, "d"),
578            Self::Zero => write!(f, "z"),
579            Self::Aggregate(td) => write!(f, ":{}", td.name),
580        }
581    }
582}
583
584/// QBE value that is accepted by instructions
585#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
586pub enum Value {
587    /// `%`-temporary
588    Temporary(String),
589    /// `$`-global
590    Global(String),
591    /// Constant
592    Const(u64),
593}
594
595impl fmt::Display for Value {
596    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
597        match self {
598            Self::Temporary(name) => write!(f, "%{name}"),
599            Self::Global(name) => write!(f, "${name}"),
600            Self::Const(value) => write!(f, "{value}"),
601        }
602    }
603}
604
605/// QBE data definition
606#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
607pub struct DataDef<'a> {
608    pub linkage: Linkage,
609    pub name: String,
610    pub align: Option<u64>,
611    pub items: Vec<(Type<'a>, DataItem)>,
612}
613
614impl<'a> DataDef<'a> {
615    pub fn new(
616        linkage: Linkage,
617        name: impl Into<String>,
618        align: Option<u64>,
619        items: Vec<(Type<'a>, DataItem)>,
620    ) -> Self {
621        Self {
622            linkage,
623            name: name.into(),
624            align,
625            items,
626        }
627    }
628}
629
630impl fmt::Display for DataDef<'_> {
631    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
632        write!(f, "{}data ${} = ", self.linkage, self.name)?;
633
634        if let Some(align) = self.align {
635            write!(f, "align {align} ")?;
636        }
637        write!(
638            f,
639            "{{ {} }}",
640            self.items
641                .iter()
642                .map(|(ty, item)| format!("{ty} {item}"))
643                .collect::<Vec<String>>()
644                .join(", ")
645        )
646    }
647}
648
649/// Data definition item
650#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
651pub enum DataItem {
652    /// Symbol and offset
653    Symbol(String, Option<u64>),
654    /// String
655    Str(String),
656    /// Constant
657    Const(u64),
658    /// Zero-initialized data of specified size
659    Zero(u64),
660}
661
662impl fmt::Display for DataItem {
663    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
664        match self {
665            Self::Symbol(name, offset) => match offset {
666                Some(off) => write!(f, "${name} +{off}"),
667                None => write!(f, "${name}"),
668            },
669            Self::Str(string) => write!(f, "\"{string}\""),
670            Self::Const(val) => write!(f, "{val}"),
671            Self::Zero(size) => write!(f, "z {size}"),
672        }
673    }
674}
675
676/// QBE aggregate type definition
677#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
678pub struct TypeDef<'a> {
679    pub name: String,
680    pub align: Option<u64>,
681    // TODO: Opaque types?
682    pub items: Vec<(Type<'a>, usize)>,
683}
684
685impl fmt::Display for TypeDef<'_> {
686    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
687        write!(f, "type :{} = ", self.name)?;
688        if let Some(align) = self.align {
689            write!(f, "align {align} ")?;
690        }
691
692        write!(
693            f,
694            "{{ {} }}",
695            self.items
696                .iter()
697                .map(|(ty, count)| if *count > 1 {
698                    format!("{ty} {count}")
699                } else {
700                    format!("{ty}")
701                })
702                .collect::<Vec<String>>()
703                .join(", "),
704        )
705    }
706}
707
708/// An IR statement
709#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
710pub enum Statement<'a> {
711    Assign(Value, Type<'a>, Instr<'a>),
712    Volatile(Instr<'a>),
713}
714
715impl fmt::Display for Statement<'_> {
716    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
717        match self {
718            Self::Assign(temp, ty, instr) => {
719                assert!(matches!(temp, Value::Temporary(_)));
720                write!(f, "{temp} ={ty} {instr}")
721            }
722            Self::Volatile(instr) => write!(f, "{instr}"),
723        }
724    }
725}
726
727/// A block of QBE instructions with a label.
728///
729/// Blocks are the basic units of control flow in QBE. Each block has a label
730/// that can be the target of jumps, and contains a sequence of instructions.
731/// A block typically ends with a control flow instruction like jump or return.
732///
733/// # Examples
734///
735/// ```rust
736/// use qbe::{Block, BlockItem, Instr, Statement, Type, Value};
737///
738/// // Create a block for a loop body
739/// let mut block = Block {
740///     label: "loop".to_string(),
741///     items: Vec::new(),
742/// };
743///
744/// // Add a helpful comment
745/// block.add_comment("Loop body - increment counter and accumulate sum");
746///
747/// // Increment loop counter: %i = %i + 1
748/// block.assign_instr(
749///     Value::Temporary("i".to_string()),
750///     Type::Word,
751///     Instr::Add(
752///         Value::Temporary("i".to_string()),
753///         Value::Const(1),
754///     ),
755/// );
756///
757/// // Update sum: %sum = %sum + %value
758/// block.assign_instr(
759///     Value::Temporary("sum".to_string()),
760///     Type::Word,
761///     Instr::Add(
762///         Value::Temporary("sum".to_string()),
763///         Value::Temporary("value".to_string()),
764///     ),
765/// );
766///
767/// // Jump to condition check block
768/// block.add_instr(Instr::Jmp("cond".to_string()));
769///
770/// // Check if block ends with a jump (it does)
771/// assert!(block.jumps());
772/// ```
773#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
774pub struct Block<'a> {
775    /// Label before the block
776    pub label: String,
777
778    /// A list of statements in the block
779    pub items: Vec<BlockItem<'a>>,
780}
781
782/// See [`Block::items`];
783#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
784pub enum BlockItem<'a> {
785    Statement(Statement<'a>),
786    Comment(String),
787}
788
789impl fmt::Display for BlockItem<'_> {
790    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
791        match self {
792            Self::Statement(stmt) => write!(f, "{stmt}"),
793            Self::Comment(comment) => write!(f, "# {comment}"),
794        }
795    }
796}
797
798impl<'a> Block<'a> {
799    pub fn add_comment(&mut self, contents: impl Into<String>) {
800        self.items.push(BlockItem::Comment(contents.into()));
801    }
802
803    /// Adds a new instruction to the block
804    pub fn add_instr(&mut self, instr: Instr<'a>) {
805        self.items
806            .push(BlockItem::Statement(Statement::Volatile(instr)));
807    }
808
809    /// Adds a new instruction assigned to a temporary
810    pub fn assign_instr(&mut self, temp: Value, ty: Type<'a>, instr: Instr<'a>) {
811        let final_type = match instr {
812            Instr::Call(_, _, _) => ty,
813            _ => ty.into_base(),
814        };
815
816        self.items.push(BlockItem::Statement(Statement::Assign(
817            temp, final_type, instr,
818        )));
819    }
820
821    /// Returns true if the block's last instruction is a jump
822    pub fn jumps(&self) -> bool {
823        let last = self.items.last();
824
825        if let Some(BlockItem::Statement(Statement::Volatile(instr))) = last {
826            matches!(instr, Instr::Ret(_) | Instr::Jmp(_) | Instr::Jnz(..))
827        } else {
828            false
829        }
830    }
831}
832
833impl fmt::Display for Block<'_> {
834    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
835        writeln!(f, "@{}", self.label)?;
836
837        write!(
838            f,
839            "{}",
840            self.items
841                .iter()
842                .map(|instr| format!("\t{instr}"))
843                .collect::<Vec<String>>()
844                .join("\n")
845        )
846    }
847}
848
849/// A QBE function definition.
850///
851/// A function consists of a name, linkage information, arguments, return type,
852/// and a collection of blocks containing the function's implementation.
853///
854/// # Examples
855///
856/// ```rust
857/// use qbe::{Function, Linkage, Type, Value, Instr, Cmp};
858///
859/// // Create a function that checks if a number is even
860/// let mut is_even = Function::new(
861///     Linkage::public(),
862///     "is_even",
863///     vec![(Type::Word, Value::Temporary("n".to_string()))],
864///     Some(Type::Word), // Returns 1 if even, 0 if odd
865/// );
866///
867/// // Add the start block
868/// let mut start = is_even.add_block("start");
869///
870/// // Calculate n % 2 (by using n & 1)
871/// start.assign_instr(
872///     Value::Temporary("remainder".to_string()),
873///     Type::Word,
874///     Instr::And(
875///         Value::Temporary("n".to_string()),
876///         Value::Const(1),
877///     ),
878/// );
879///
880/// // Check if remainder is 0 (even number)
881/// start.assign_instr(
882///     Value::Temporary("is_zero".to_string()),
883///     Type::Word,
884///     Instr::Cmp(
885///         Type::Word,
886///         Cmp::Eq,
887///         Value::Temporary("remainder".to_string()),
888///         Value::Const(0),
889///     ),
890/// );
891///
892/// // Return the result
893/// start.add_instr(Instr::Ret(Some(Value::Temporary("is_zero".to_string()))));
894/// ```
895#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
896pub struct Function<'a> {
897    /// Function's linkage
898    pub linkage: Linkage,
899
900    /// Function name
901    pub name: String,
902
903    /// Function arguments
904    pub arguments: Vec<(Type<'a>, Value)>,
905
906    /// Return type
907    pub return_ty: Option<Type<'a>>,
908
909    /// Labelled blocks
910    pub blocks: Vec<Block<'a>>,
911}
912
913impl<'a> Function<'a> {
914    /// Instantiates an empty function and returns it
915    pub fn new(
916        linkage: Linkage,
917        name: impl Into<String>,
918        arguments: Vec<(Type<'a>, Value)>,
919        return_ty: Option<Type<'a>>,
920    ) -> Self {
921        Function {
922            linkage,
923            name: name.into(),
924            arguments,
925            return_ty,
926            blocks: Vec::new(),
927        }
928    }
929
930    /// Adds a new empty block with a specified label and returns a reference to it
931    pub fn add_block(&mut self, label: impl Into<String>) -> &mut Block<'a> {
932        self.blocks.push(Block {
933            label: label.into(),
934            items: Vec::new(),
935        });
936        self.blocks.last_mut().unwrap()
937    }
938
939    /// Returns a reference to the last block
940    #[deprecated(
941        since = "3.0.0",
942        note = "Use `self.blocks.last()` or `self.blocks.last_mut()` instead."
943    )]
944    pub fn last_block(&mut self) -> &Block {
945        self.blocks
946            .last()
947            .expect("Function must have at least one block")
948    }
949
950    /// Adds a new instruction to the last block
951    pub fn add_instr(&mut self, instr: Instr<'a>) {
952        self.blocks
953            .last_mut()
954            .expect("Last block must be present")
955            .add_instr(instr);
956    }
957
958    /// Adds a new instruction assigned to a temporary
959    pub fn assign_instr(&mut self, temp: Value, ty: Type<'a>, instr: Instr<'a>) {
960        self.blocks
961            .last_mut()
962            .expect("Last block must be present")
963            .assign_instr(temp, ty, instr);
964    }
965}
966
967impl fmt::Display for Function<'_> {
968    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
969        write!(f, "{}function", self.linkage)?;
970        if let Some(ty) = &self.return_ty {
971            write!(f, " {ty}")?;
972        }
973
974        writeln!(
975            f,
976            " ${name}({args}) {{",
977            name = self.name,
978            args = self
979                .arguments
980                .iter()
981                .map(|(ty, temp)| format!("{ty} {temp}"))
982                .collect::<Vec<String>>()
983                .join(", "),
984        )?;
985
986        for blk in self.blocks.iter() {
987            writeln!(f, "{blk}")?;
988        }
989
990        write!(f, "}}")
991    }
992}
993
994/// Linkage of a function or data defintion (e.g. section and
995/// private/public status)
996#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
997pub struct Linkage {
998    /// Specifies whether the target is going to be accessible publicly
999    pub exported: bool,
1000
1001    /// Specifies target's section
1002    pub section: Option<String>,
1003
1004    /// Specifies target's section flags
1005    pub secflags: Option<String>,
1006
1007    /// Specifies whether the target is stored in thread-local storage
1008    pub thread_local: bool,
1009}
1010
1011impl Linkage {
1012    /// Returns the default configuration for private linkage
1013    pub fn private() -> Linkage {
1014        Linkage {
1015            exported: false,
1016            section: None,
1017            secflags: None,
1018            thread_local: false,
1019        }
1020    }
1021
1022    /// Returns the configuration for private linkage with a provided section
1023    pub fn private_with_section(section: impl Into<String>) -> Linkage {
1024        Linkage {
1025            exported: false,
1026            section: Some(section.into()),
1027            secflags: None,
1028            thread_local: false,
1029        }
1030    }
1031
1032    /// Returns the default configuration for public linkage
1033    pub fn public() -> Linkage {
1034        Linkage {
1035            exported: true,
1036            section: None,
1037            secflags: None,
1038            thread_local: false,
1039        }
1040    }
1041
1042    /// Returns the configuration for public linkage with a provided section
1043    pub fn public_with_section(section: impl Into<String>) -> Linkage {
1044        Linkage {
1045            exported: true,
1046            section: Some(section.into()),
1047            secflags: None,
1048            thread_local: false,
1049        }
1050    }
1051
1052    pub fn thread_local() -> Linkage {
1053        Linkage {
1054            exported: false,
1055            thread_local: true,
1056            section: None,
1057            secflags: None,
1058        }
1059    }
1060
1061    pub fn exported_thread_local() -> Linkage {
1062        Linkage {
1063            exported: true,
1064            thread_local: true,
1065            section: None,
1066            secflags: None,
1067        }
1068    }
1069
1070    pub fn thread_local_with_section(section: impl Into<String>) -> Linkage {
1071        Linkage {
1072            exported: false,
1073            thread_local: true,
1074            section: Some(section.into()),
1075            secflags: None,
1076        }
1077    }
1078}
1079
1080impl fmt::Display for Linkage {
1081    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1082        if self.exported {
1083            write!(f, "export ")?;
1084        }
1085        if self.thread_local {
1086            write!(f, "thread ")?;
1087        }
1088        if let Some(section) = &self.section {
1089            // TODO: escape it, possibly
1090            write!(f, "section \"{section}\"")?;
1091            if let Some(secflags) = &self.secflags {
1092                write!(f, " \"{secflags}\"")?;
1093            }
1094            write!(f, " ")?;
1095        }
1096
1097        Ok(())
1098    }
1099}
1100
1101/// A complete QBE IL module.
1102///
1103/// A module contains all the functions, data definitions, and type definitions
1104/// that make up a QBE IL file. When converted to a string, it produces valid
1105/// QBE IL code that can be compiled by QBE.
1106///
1107/// # Examples
1108///
1109/// ```rust
1110/// use qbe::{Module, Function, DataDef, TypeDef, Linkage, Type, Value, Instr, DataItem};
1111///
1112/// // Create a new module
1113/// let mut module = Module::new();
1114///
1115/// // Add a string constant
1116/// let hello_str = DataDef::new(
1117///     Linkage::private(),
1118///     "hello",
1119///     None,
1120///     vec![
1121///         (Type::Byte, DataItem::Str("Hello, World!\n".to_string())),
1122///         (Type::Byte, DataItem::Const(0)), // Null terminator
1123///     ],
1124/// );
1125/// module.add_data(hello_str);
1126///
1127/// // Add a main function that prints the string
1128/// let mut main = Function::new(
1129///     Linkage::public(),
1130///     "main",
1131///     vec![],
1132///     Some(Type::Word),
1133/// );
1134///
1135/// let mut start = main.add_block("start");
1136///
1137/// // Call printf with the string: %r = call $printf(l $hello)
1138/// start.assign_instr(
1139///     Value::Temporary("r".to_string()),
1140///     Type::Word,
1141///     Instr::Call(
1142///         "printf".to_string(),
1143///         vec![(Type::Long, Value::Global("hello".to_string()))],
1144///         None,
1145///     ),
1146/// );
1147///
1148/// // Return 0
1149/// start.add_instr(Instr::Ret(Some(Value::Const(0))));
1150///
1151/// // Add the function to the module
1152/// module.add_function(main);
1153/// ```
1154#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
1155pub struct Module<'a> {
1156    pub functions: Vec<Function<'a>>,
1157    pub types: Vec<TypeDef<'a>>,
1158    pub data: Vec<DataDef<'a>>,
1159}
1160
1161impl<'a> Module<'a> {
1162    /// Creates a new module
1163    pub fn new() -> Module<'a> {
1164        Module {
1165            functions: Vec::new(),
1166            types: Vec::new(),
1167            data: Vec::new(),
1168        }
1169    }
1170
1171    /// Adds a function to the module, returning a reference to it for later
1172    /// modification
1173    pub fn add_function(&mut self, func: Function<'a>) -> &mut Function<'a> {
1174        self.functions.push(func);
1175        self.functions.last_mut().unwrap()
1176    }
1177
1178    /// Adds a type definition to the module, returning a reference to it for
1179    /// later modification
1180    pub fn add_type(&mut self, def: TypeDef<'a>) -> &mut TypeDef<'a> {
1181        self.types.push(def);
1182        self.types.last_mut().unwrap()
1183    }
1184
1185    /// Adds a data definition to the module
1186    pub fn add_data(&mut self, data: DataDef<'a>) -> &mut DataDef<'a> {
1187        self.data.push(data);
1188        self.data.last_mut().unwrap()
1189    }
1190}
1191
1192impl fmt::Display for Module<'_> {
1193    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1194        for ty in self.types.iter() {
1195            writeln!(f, "{ty}")?;
1196        }
1197        for func in self.functions.iter() {
1198            writeln!(f, "{func}")?;
1199        }
1200        for data in self.data.iter() {
1201            writeln!(f, "{data}")?;
1202        }
1203        Ok(())
1204    }
1205}