Skip to main content

rucc_asm/
lib.rs

1//! Instruction encoders, the integrated assembler, inline assembly and relaxation.
2//!
3//! Design: `spec/11-asm-objects-debug.md`. Layer rank 10, see `spec/18-package-layout.md`.
4//!
5//! # Status
6//!
7//! What is written is the assembly text `-S` produces, which section 11.1 asks for because
8//! people read it. It is written from the instruction description in `rucc-target`, the same one
9//! the encoder will be generated from, so the listing and the object file cannot come to
10//! disagree about what an instruction is.
11//!
12//! The encoder itself, the assembler that reads `.s` and `.S`, inline assembly and relaxation
13//! are the rest of M3 and M4 and are not here yet.
14//!
15//! Every crate in the workspace is published, and publishing implies a promise. This one is
16//! tier 3: its Rust API is explicitly unstable and will change without a major version bump.
17//! Depend on the `rucc` binary's behaviour, not on this.
18
19#![doc(html_root_url = "https://docs.rs/rucc-asm/0.3.5")]
20
21mod att;
22mod format;
23
24pub use crate::att::print;
25pub use crate::format::Directives;
26
27use std::fmt;
28
29/// The milestone in `spec/17-milestones.md` that fills this crate in.
30pub const MILESTONE: &str = "M3";
31
32/// A function this compiler could not write out as assembly.
33///
34/// Neither of these is a program's fault and neither should ever reach a user, since a machine
35/// function that reaches here has been through the whole backend and the tests pin both of the
36/// claims below. They are errors rather than assertions because the alternative to reporting one
37/// is writing a listing that is quietly wrong, and a wrong listing is the failure section 11.1 is
38/// written to prevent.
39#[derive(Debug, Clone, PartialEq, Eq)]
40pub enum Error {
41    /// An opcode the target has no description of.
42    Opcode {
43        /// The function it turned up in.
44        func: String,
45        /// The opcode, as the machine IR spells it.
46        opcode: String,
47    },
48    /// A register that is still virtual, which is a function that was never allocated.
49    Virtual {
50        /// The function it turned up in.
51        func: String,
52        /// The opcode the register is an operand of.
53        opcode: String,
54    },
55    /// A machine this crate cannot write assembly for.
56    Machine {
57        /// The triple that was asked for.
58        triple: String,
59    },
60}
61
62impl fmt::Display for Error {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        match self {
65            Error::Opcode { func, opcode } => {
66                write!(f, "'{func}' has a '{opcode}' and the target does not say what one is")
67            }
68            Error::Virtual { func, opcode } => {
69                write!(f, "'{func}' reached the assembler with a virtual register in a '{opcode}'")
70            }
71            Error::Machine { triple } => {
72                write!(f, "there is no assembly writer for {triple} in this compiler yet")
73            }
74        }
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    #[test]
81    fn milestone_is_recorded() {
82        assert!(super::MILESTONE.starts_with('M'));
83    }
84}