Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[alias]
autogen = "run --bin autogen --release --"
dis = "run -p rspirv2-tools --bin rspirv2-dis -q --"
dis = "run -p rspirv2-tools --bin rspirv2-dis --release -q --"
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ clap = { version = "4.5.57", features = ["derive"] }
anstream = "0.6.21"
anstyle = "1.0.13"
expect-test = "1.5.1"
rustc-hash = "2.1.1"

[workspace.lints.rust]
#missing_docs = "warn"
Expand Down
38 changes: 27 additions & 11 deletions crates/grammar-parser/src/codegen/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,26 @@ pub fn write_inst(writer: &mut GrammarWriter, grammar: &Grammar<'_>) -> anyhow::
let reader = (!members.is_empty()).then(|| quote!(let mut op_reader = ));

// disassembly
let (dis_id_result_pat, dis_id_result_value) = if let Some(id_result) = id_result {
let name = &id_result.name;
("{} = ", Some(quote!(, self.#name.dis(_ctx))))
} else {
("", None)
let dis_operand_ctx = {
let id_result_opt = if let Some(id_result) = id_result {
let name = &id_result.name;
quote!(self.#name)
} else {
quote!(None)
};
let id_result_type_opt = if let Some(id_result_type) = id_result_type {
let name = &id_result_type.name;
quote!(Some(self.#name))
} else {
quote!(None)
};
quote! {
let ctx = &OperandDisContext {
id_result: #id_result_opt,
id_result_type: #id_result_type_opt,
ctx,
};
}
};
// `name: Ident` is a good key to filter out the id_result, as names must be unique anyway
let operands_without_result_id = member_operands
Expand All @@ -63,10 +78,10 @@ pub fn write_inst(writer: &mut GrammarWriter, grammar: &Grammar<'_>) -> anyhow::
.iter()
.map(|op| {
let name = &op.name;
quote!(, self.#name.dis(_ctx))
quote!(, self.#name.dis(ctx))
})
.collect::<Vec<_>>();
let pat = [dis_id_result_pat, inst.opname.as_ref()]
let pat = ["{}", inst.opname.as_ref()]
.into_iter()
.chain(
operands_without_result_id
Expand All @@ -84,7 +99,7 @@ pub fn write_inst(writer: &mut GrammarWriter, grammar: &Grammar<'_>) -> anyhow::
)
.collect::<String>();
let rspirv_spaces_prefix = if id_result_type.is_some() {
quote!(let rspirv_space = _ctx.rspirv_space();)
quote!(let rspirv_space = ctx.rspirv_space();)
} else {
quote!()
};
Expand Down Expand Up @@ -121,9 +136,10 @@ pub fn write_inst(writer: &mut GrammarWriter, grammar: &Grammar<'_>) -> anyhow::
})
}

fn dis_fmt(&self, f: &mut Formatter<'_>, _ctx: &DisContext) -> std::fmt::Result {
fn dis_fmt(&self, f: &mut Formatter<'_>, ctx: &DisContext) -> std::fmt::Result {
#dis_operand_ctx
#rspirv_spaces_prefix
write!(f, #pat #dis_id_result_value #(#dis_operands_value)*)
write!(f, #pat, ctx.id_result_writer() #(#dis_operands_value)*)
}
}
}
Expand Down Expand Up @@ -196,7 +212,7 @@ pub fn write_inst_enum(
let opcode = reader.opcode();
Ok(match opcode {
#(#decode_match)*
_ => return Err(DecodeError::UnknownOpCode { opcode }),
_ => return Err(DecodeErrorKind::UnknownOpCode { opcode }.into()),
})
}

Expand Down
18 changes: 9 additions & 9 deletions crates/grammar-parser/src/codegen/operands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,15 @@ fn emit_rust_like_enum(
let variant = reader.pull()?.0;
Ok(match variant {
#(#decode,)*
_ => return Err(DecodeError::UnknownEnumVariant {
_ => return Err(DecodeErrorKind::UnknownEnumVariant {
name: stringify!(#name),
variant,
})
}.into())
})
}

#[inline]
fn dis_fmt(&self, f: &mut Formatter<'_>, _ctx: &DisContext) -> std::fmt::Result {
fn dis_fmt(&self, f: &mut Formatter<'_>, _ctx: &OperandDisContext<'_>) -> std::fmt::Result {
match self {
#(#dis),*
}
Expand Down Expand Up @@ -211,15 +211,15 @@ fn emit_c_like_enum(operand_kind: &OperandKind<'_>, enumerants: &[Enumerant<'_>]
let variant = reader.pull()?.0;
Ok(match variant {
#(#decode,)*
_ => return Err(DecodeError::UnknownEnumVariant {
_ => return Err(DecodeErrorKind::UnknownEnumVariant {
name: stringify!(#name),
variant,
})
}.into())
})
}

#[inline]
fn dis_fmt(&self, f: &mut Formatter<'_>, _: &DisContext) -> std::fmt::Result {
fn dis_fmt(&self, f: &mut Formatter<'_>, _: &OperandDisContext<'_>) -> std::fmt::Result {
match self {
#(#dis),*
}
Expand Down Expand Up @@ -298,7 +298,7 @@ fn emit_bitflags_enum(operand_kind: &OperandKind<'_>, enumerants: &[Enumerant<'_
}

#[inline]
fn dis_fmt(&self, f: &mut Formatter<'_>, _: &DisContext) -> std::fmt::Result {
fn dis_fmt(&self, f: &mut Formatter<'_>, _: &OperandDisContext<'_>) -> std::fmt::Result {
if self.is_empty() {
write!(f, " None")
} else {
Expand Down Expand Up @@ -329,7 +329,7 @@ fn emit_composite(operand_kind: &OperandKind<'_>, bases: &[Cow<'_, str>]) -> Tok
quote!(OperandEncoding::encode(&self.#i, &mut *writer)?)
});
let decode = (0..bases.len()).map(|_| quote!(OperandEncoding::decode(&mut *reader)?));
let dis_pat = (0..bases.len()).map(|_| " {}").collect::<String>();
let dis_pat = (0..bases.len()).map(|_| "{}").collect::<String>();
let dis_values = (0..bases.len()).map(|i| {
let i = proc_macro2::Literal::usize_unsuffixed(i);
quote!(OperandEncoding::dis(&self.#i, ctx))
Expand Down Expand Up @@ -357,7 +357,7 @@ fn emit_composite(operand_kind: &OperandKind<'_>, bases: &[Cow<'_, str>]) -> Tok
}

#[inline]
fn dis_fmt(&self, f: &mut Formatter<'_>, ctx: &DisContext) -> std::fmt::Result {
fn dis_fmt(&self, f: &mut Formatter<'_>, ctx: &OperandDisContext<'_>) -> std::fmt::Result {
write!(f, #dis_pat, #(#dis_values),*)
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/rspirv2-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ bytemuck = { workspace = true, optional = true }
bitflags.workspace = true
smallvec.workspace = true
anstyle.workspace = true
rustc-hash.workspace = true

[dev-dependencies]
anyhow.workspace = true
Expand Down
62 changes: 53 additions & 9 deletions crates/rspirv2-types/src/binary/decode_error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::binary::InstOffset;
use bitflags::Flags;
use std::error::Error;
use std::ffi::FromBytesUntilNulError;
Expand All @@ -6,7 +7,7 @@ use std::str::Utf8Error;
use std::string::FromUtf8Error;

#[derive(Clone, PartialEq)]
pub enum DecodeError {
pub enum DecodeErrorKind {
UnknownOpCode {
opcode: u16,
},
Expand Down Expand Up @@ -55,7 +56,7 @@ pub enum DecodeError {
},
}

impl Display for DecodeError {
impl Display for DecodeErrorKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::UnknownOpCode { opcode } => write!(
Expand Down Expand Up @@ -139,39 +140,82 @@ impl Display for DecodeError {
}
}

impl Debug for DecodeError {
impl Debug for DecodeErrorKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(self, f)
}
}

impl Error for DecodeError {}
impl Error for DecodeErrorKind {}

#[derive(Clone, PartialEq)]
pub struct DecodeError {
pub kind: DecodeErrorKind,
pub inst_offset: Option<InstOffset>,
}

impl DecodeError {
#[inline]
pub fn new(kind: DecodeErrorKind) -> Self {
Self {
kind,
inst_offset: None,
}
}

#[inline]
pub fn with_inst_offset(mut self, offset: impl Into<Option<InstOffset>>) -> Self {
self.inst_offset = offset.into();
self
}

#[inline]
pub fn invalid_bitflags<T: Flags<Bits = u32>>(name: &'static str, bits: u32) -> Self {
Self::InvalidBitflags {
Self::new(DecodeErrorKind::InvalidBitflags {
name,
unknown: bits & T::all().bits(),
bits,
}
})
}
}

impl From<DecodeErrorKind> for DecodeError {
fn from(variant: DecodeErrorKind) -> Self {
Self::new(variant)
}
}

impl From<FromBytesUntilNulError> for DecodeError {
fn from(_: FromBytesUntilNulError) -> Self {
Self::StringNotNulTerminated
Self::new(DecodeErrorKind::StringNotNulTerminated)
}
}

impl From<Utf8Error> for DecodeError {
fn from(value: Utf8Error) -> Self {
Self::Utf8Error(value)
Self::new(DecodeErrorKind::Utf8Error(value))
}
}

impl From<FromUtf8Error> for DecodeError {
fn from(value: FromUtf8Error) -> Self {
Self::Utf8Error(value.utf8_error())
Self::new(DecodeErrorKind::Utf8Error(value.utf8_error()))
}
}

impl Display for DecodeError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if let Some(inst_offset) = self.inst_offset {
write!(f, "Instruction at offset {inst_offset}: ")?;
}
write!(f, "{}", self.kind)
}
}

impl Debug for DecodeError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(self, f)
}
}

impl Error for DecodeError {}
21 changes: 12 additions & 9 deletions crates/rspirv2-types/src/binary/reader.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::Word;
use crate::binary::DecodeError;
use crate::binary::{DecodeError, DecodeErrorKind};
use crate::meta::InstMeta;
use std::cmp::Ordering;
use std::fmt::{Display, Formatter};
Expand Down Expand Up @@ -39,15 +39,15 @@ impl<'a> InstReader<'a> {
/// words not associated with this instruction. Use [`Self::len`] to figure out how many words have been consumed
/// by this instruction.
pub fn from_words(words: &'a [Word]) -> Result<Self, DecodeError> {
let first = words.first().ok_or(DecodeError::OutOfInstructions)?;
let first = words.first().ok_or(DecodeErrorKind::OutOfInstructions)?;
let (_, op_len) = first.to_op();
if op_len == 0 {
// len must at least be 1, as it includes the op Word itself
return Err(DecodeError::InstructionZeroSized);
return Err(DecodeErrorKind::InstructionZeroSized.into());
}
let inst_words = words
.get(0..op_len)
.ok_or(DecodeError::InstructionTooLong {
.ok_or(DecodeErrorKind::InstructionTooLong {
op_len,
module_remaining: words.len(),
})?;
Expand All @@ -72,11 +72,12 @@ impl<'a> InstReader<'a> {
pub fn check_opcode(&self, meta: &InstMeta) -> Result<OperandReader<'a>, DecodeError> {
let opcode = self.opcode();
if opcode != meta.opcode {
Err(DecodeError::WrongOpCode {
Err(DecodeErrorKind::WrongOpCode {
name: meta.opname,
expected: meta.opcode,
actual: opcode,
})
}
.into())
} else {
Ok(self.operand_reader())
}
Expand Down Expand Up @@ -142,19 +143,21 @@ impl<'a> OperandReader<'a> {
pub fn finalize(&self) -> Result<(), DecodeError> {
let remaining = self.remaining();
match 0.cmp(&remaining) {
Ordering::Less => Err(DecodeError::InstructionWithAdditionalOperants {
Ordering::Less => Err(DecodeErrorKind::InstructionWithAdditionalOperants {
param_len: self.params.len(),
remaining,
}),
}
.into()),
Ordering::Equal => Ok(()),
Ordering::Greater => Err(self.err_too_many_words()),
}
}

fn err_too_many_words(&self) -> DecodeError {
DecodeError::InstructionDecodePulledTooManyWords {
DecodeErrorKind::InstructionDecodePulledTooManyWords {
param_len: self.len(),
}
.into()
}

/// View the *remaining* Words as a slice, does not advance the `params_offset`.
Expand Down
Loading
Loading