1pub mod lift;
6pub mod lower;
7pub mod print;
8pub mod read;
9pub mod spec;
10pub mod write;
11
12use crate::{FxIndexMap, InternedStr};
13use smallvec::SmallVec;
14use std::collections::{BTreeMap, BTreeSet};
15use std::iter;
16use std::num::NonZeroU32;
17use std::string::FromUtf8Error;
18
19#[derive(Clone)]
21pub struct Dialect {
22 pub version_major: u8,
23 pub version_minor: u8,
24
25 pub capabilities: BTreeSet<u32>,
26 pub extensions: BTreeSet<String>,
27
28 pub addressing_model: u32,
29 pub memory_model: u32,
30}
31
32#[derive(Clone)]
34pub struct ModuleDebugInfo {
35 pub original_generator_magic: Option<NonZeroU32>,
36
37 pub source_languages: BTreeMap<DebugSourceLang, DebugSources>,
38 pub source_extensions: Vec<String>,
39 pub module_processes: Vec<String>,
40}
41
42#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
43pub struct DebugSourceLang {
44 pub lang: u32,
45 pub version: u32,
46}
47
48#[derive(Clone, Default)]
49pub struct DebugSources {
50 pub file_contents: FxIndexMap<InternedStr, String>,
51}
52
53#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
55pub struct Inst {
56 pub opcode: spec::Opcode,
57
58 pub imms: SmallVec<[Imm; 2]>,
64}
65
66impl From<spec::Opcode> for Inst {
67 fn from(opcode: spec::Opcode) -> Self {
68 Self { opcode, imms: SmallVec::new() }
69 }
70}
71
72pub struct InstWithIds {
74 pub without_ids: Inst,
75
76 pub result_type_id: Option<Id>,
78 pub result_id: Option<Id>,
79
80 pub ids: SmallVec<[Id; 4]>,
82}
83
84impl std::ops::Deref for InstWithIds {
86 type Target = Inst;
87 fn deref(&self) -> &Inst {
88 &self.without_ids
89 }
90}
91impl std::ops::DerefMut for InstWithIds {
92 fn deref_mut(&mut self) -> &mut Inst {
93 &mut self.without_ids
94 }
95}
96
97#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
102pub enum Imm {
103 Short(spec::OperandKind, u32),
104 LongStart(spec::OperandKind, u32),
105 LongCont(spec::OperandKind, u32),
106}
107
108pub type Id = NonZeroU32;
110
111pub fn extract_literal_string(imms: &[Imm]) -> Result<String, FromUtf8Error> {
118 let wk = &spec::Spec::get().well_known;
119
120 let mut words = match *imms {
121 [Imm::Short(kind, first_word)] | [Imm::LongStart(kind, first_word), ..] => {
122 assert_eq!(kind, wk.LiteralString);
123 iter::once(first_word).chain(imms[1..].iter().map(|&imm| match imm {
124 Imm::LongCont(kind, word) => {
125 assert_eq!(kind, wk.LiteralString);
126 word
127 }
128 _ => unreachable!(),
129 }))
130 }
131 _ => unreachable!(),
132 };
133
134 let mut bytes = Vec::with_capacity(imms.len() * 4);
135 while let Some(word) = words.next() {
136 for byte in word.to_le_bytes() {
137 if byte == 0 {
138 assert!(words.next().is_none());
139 return String::from_utf8(bytes);
140 }
141 bytes.push(byte);
142 }
143 }
144 unreachable!("missing \\0 terminator in LiteralString");
145}
146
147pub fn encode_literal_string(s: &str) -> impl Iterator<Item = Imm> + '_ {
149 let wk = &spec::Spec::get().well_known;
150
151 let bytes = s.as_bytes();
152
153 let full_words = bytes.chunks_exact(4).map(|w| <[u8; 4]>::try_from(w).unwrap());
155
156 let leftover_bytes = &bytes[full_words.len() * 4..];
157 let mut last_word = [0; 4];
158 last_word[..leftover_bytes.len()].copy_from_slice(leftover_bytes);
159
160 let total_words = full_words.len() + 1;
161
162 full_words.chain(iter::once(last_word)).map(u32::from_le_bytes).enumerate().map(
163 move |(i, word)| {
164 let kind = wk.LiteralString;
165 match (i, total_words) {
166 (0, 1) => Imm::Short(kind, word),
167 (0, _) => Imm::LongStart(kind, word),
168 (_, _) => Imm::LongCont(kind, word),
169 }
170 },
171 )
172}