pub mod lift;
pub mod lower;
pub mod print;
pub mod read;
pub mod spec;
pub mod write;
use crate::{FxIndexMap, InternedStr};
use smallvec::SmallVec;
use std::collections::{BTreeMap, BTreeSet};
use std::iter;
use std::num::NonZeroU32;
use std::string::FromUtf8Error;
#[derive(Clone)]
pub struct Dialect {
pub version_major: u8,
pub version_minor: u8,
pub capabilities: BTreeSet<u32>,
pub extensions: BTreeSet<String>,
pub addressing_model: u32,
pub memory_model: u32,
}
#[derive(Clone)]
pub struct ModuleDebugInfo {
pub original_generator_magic: Option<NonZeroU32>,
pub source_languages: BTreeMap<DebugSourceLang, DebugSources>,
pub source_extensions: Vec<String>,
pub module_processes: Vec<String>,
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct DebugSourceLang {
pub lang: u32,
pub version: u32,
}
#[derive(Clone, Default)]
pub struct DebugSources {
pub file_contents: FxIndexMap<InternedStr, String>,
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Inst {
pub opcode: spec::Opcode,
pub imms: SmallVec<[Imm; 2]>,
}
impl From<spec::Opcode> for Inst {
fn from(opcode: spec::Opcode) -> Self {
Self { opcode, imms: SmallVec::new() }
}
}
pub struct InstWithIds {
pub without_ids: Inst,
pub result_type_id: Option<Id>,
pub result_id: Option<Id>,
pub ids: SmallVec<[Id; 4]>,
}
impl std::ops::Deref for InstWithIds {
type Target = Inst;
fn deref(&self) -> &Inst {
&self.without_ids
}
}
impl std::ops::DerefMut for InstWithIds {
fn deref_mut(&mut self) -> &mut Inst {
&mut self.without_ids
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Imm {
Short(spec::OperandKind, u32),
LongStart(spec::OperandKind, u32),
LongCont(spec::OperandKind, u32),
}
pub type Id = NonZeroU32;
pub fn extract_literal_string(imms: &[Imm]) -> Result<String, FromUtf8Error> {
let wk = &spec::Spec::get().well_known;
let mut words = match *imms {
[Imm::Short(kind, first_word)] | [Imm::LongStart(kind, first_word), ..] => {
assert_eq!(kind, wk.LiteralString);
iter::once(first_word).chain(imms[1..].iter().map(|&imm| match imm {
Imm::LongCont(kind, word) => {
assert_eq!(kind, wk.LiteralString);
word
}
_ => unreachable!(),
}))
}
_ => unreachable!(),
};
let mut bytes = Vec::with_capacity(imms.len() * 4);
while let Some(word) = words.next() {
for byte in word.to_le_bytes() {
if byte == 0 {
assert!(words.next().is_none());
return String::from_utf8(bytes);
}
bytes.push(byte);
}
}
unreachable!("missing \\0 terminator in LiteralString");
}
pub fn encode_literal_string(s: &str) -> impl Iterator<Item = Imm> + '_ {
let wk = &spec::Spec::get().well_known;
let bytes = s.as_bytes();
let full_words = bytes.chunks_exact(4).map(|w| <[u8; 4]>::try_from(w).unwrap());
let leftover_bytes = &bytes[full_words.len() * 4..];
let mut last_word = [0; 4];
last_word[..leftover_bytes.len()].copy_from_slice(leftover_bytes);
let total_words = full_words.len() + 1;
full_words.chain(iter::once(last_word)).map(u32::from_le_bytes).enumerate().map(
move |(i, word)| {
let kind = wk.LiteralString;
match (i, total_words) {
(0, 1) => Imm::Short(kind, word),
(0, _) => Imm::LongStart(kind, word),
(_, _) => Imm::LongCont(kind, word),
}
},
)
}