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}