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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/target
/.idea
**/*.spv
**/*.dis*
7 changes: 2 additions & 5 deletions crates/examples/src/bin/debug_dis.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use clap::Parser;
use rspirv2::core::inst_set::CoreInstSet;
use rspirv2::inst::InstEncoding;
use rspirv2::module::Module;
use std::path::PathBuf;

Expand All @@ -13,10 +12,8 @@ pub struct Args {
impl Args {
pub fn run(&self) -> anyhow::Result<()> {
let binary = std::fs::read(&self.path)?;
let module = Module::from_bytes(binary.as_slice())?;
let mut module_reader = module.reader();
while let Some(inst) = module_reader.next()? {
let inst = CoreInstSet::decode(inst)?;
let module = Module::<CoreInstSet>::from_bytes(binary.as_slice())?;
for inst in module.iter() {
println!("{:?}", inst);
}
Ok(())
Expand Down
15 changes: 6 additions & 9 deletions crates/examples/src/bin/print_spec_constants.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use clap::Parser;
use rspirv2::core::inst::{OpName, OpSpecConstant};
use rspirv2::inst::InstEncoding;
use rspirv2::core::inst_set::CoreInstSet;
use rspirv2::module::Module;
use rspirv2::operand::IdResult;
use std::collections::HashMap;
Expand All @@ -14,20 +13,18 @@ pub struct Args {

impl Args {
pub fn run(&self, f: &mut impl std::io::Write) -> anyhow::Result<()> {
let module = Module::from_bytes(std::fs::read(&self.path)?.as_slice())?;
let module = Module::<CoreInstSet>::from_bytes(std::fs::read(&self.path)?.as_slice())?;

let mut names = HashMap::<IdResult, String>::new();
let mut module_reader = module.reader();
while let Some(inst) = module_reader.next()? {
if let Some(inst) = OpName::try_decode(inst)? {
for inst in module.iter() {
if let CoreInstSet::Name(inst) = inst {
names.insert(inst.target.0, inst.name.0);
}
}

let mut spec_const_name_to_value = HashMap::<String, _>::new();
let mut module_reader = module.reader();
while let Some(inst) = module_reader.next()? {
if let Some(inst) = OpSpecConstant::try_decode(inst)?
for inst in module.iter() {
if let CoreInstSet::SpecConstant(inst) = inst
&& let Some(name) = names.get(&inst.id_result.unwrap())
{
spec_const_name_to_value.insert(name.clone(), inst.value.as_u32()?);
Expand Down
4 changes: 4 additions & 0 deletions crates/grammar-parser/src/codegen/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ pub fn write_inst_enum(
}

impl InstEncoding for #name {
fn name() -> &'static str {
stringify!(#name)
}

fn encode(&self, writer: &mut impl WordWriter) -> Result<(), EncodeError> {
match self {
#(#encode_match)*
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 @@ -18,3 +18,4 @@ anstyle.workspace = true

[dev-dependencies]
anyhow.workspace = true
bytemuck.workspace = true
2 changes: 1 addition & 1 deletion crates/rspirv2-types/src/binary/decode_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::fmt::{Debug, Display, Formatter};
use std::str::Utf8Error;
use std::string::FromUtf8Error;

#[derive(Clone)]
#[derive(Clone, PartialEq)]
pub enum DecodeError {
UnknownOpCode {
opcode: u16,
Expand Down
37 changes: 20 additions & 17 deletions crates/rspirv2-types/src/binary/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,31 @@ use crate::Word;
use crate::binary::DecodeError;
use crate::meta::InstMeta;
use std::cmp::Ordering;
use std::fmt::{Display, Formatter};
use std::ops::{Deref, DerefMut};

/// Reader for an entire module
pub struct ModuleReader<'a> {
words: &'a [Word],
offset: usize,
/// An offset to some instruction, a wrapper around `usize`.
#[repr(transparent)]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct InstOffset(pub usize);

impl Deref for InstOffset {
type Target = usize;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<'a> ModuleReader<'a> {
pub fn new(words: &'a [Word]) -> Self {
Self { words, offset: 0 }
impl DerefMut for InstOffset {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Result<Option<InstReader<'a>>, DecodeError> {
match InstReader::from_words(&self.words[self.offset..]) {
Ok(inst_reader) => {
self.offset += inst_reader.len();
Ok(Some(inst_reader))
}
Err(DecodeError::OutOfInstructions) => Ok(None),
Err(e) => Err(e),
}
impl Display for InstOffset {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)
}
}

Expand Down
34 changes: 0 additions & 34 deletions crates/rspirv2-types/src/dis.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
//! Module for Disassembly

use crate::Word;
use crate::binary::{DecodeError, ModuleReader};
use crate::inst::InstEncoding;
use crate::operand::LiteralStringEscape;
use anstyle::Style;
use std::cell::Cell;
use std::fmt::{Display, Formatter};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};

/// Options for disassembly
Expand Down Expand Up @@ -100,36 +96,6 @@ impl DerefMut for DisContext {
}
}

/// A sequence of words that has been pre-processed and may be [`Display`]ed.
///
/// The `ISA: `[`InstEncoding`] generic determines for which instruction set these Words are disassembled.
pub struct DisModule<'a, ISA: InstEncoding> {
words: &'a [Word],
dis: DisContext,
_phantom: PhantomData<ISA>,
}

impl<'a, ISA: InstEncoding> DisModule<'a, ISA> {
pub fn new(words: &'a [Word], opt: DisOptions) -> Result<Self, DecodeError> {
Ok(Self {
words,
dis: DisContext::new(opt),
_phantom: PhantomData,
})
}
}

impl<'a, ISA: InstEncoding> Display for DisModule<'a, ISA> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut reader = ModuleReader::new(self.words);
while let Some(inst) = reader.next().map_err(|_| std::fmt::Error)? {
let inst = ISA::decode(inst).map_err(|_| std::fmt::Error)?;
writeln!(f, "{}", inst.dis(&self.dis))?;
}
Ok(())
}
}

/// Utility struct for inserting separators between variants. Use it like `format!({sep}{value})`, will skip the
/// separator on first write.
///
Expand Down
80 changes: 80 additions & 0 deletions crates/rspirv2-types/src/inst.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::Word;
use crate::binary::{DecodeError, EncodeError, IdResultAlloc, InstReader, WordWriter};
use crate::dis::DisContext;
use crate::meta::InstMeta;
use crate::operand::{IdResult, OptionIdResult};
use std::fmt::{Debug, Display, Formatter};
use std::marker::PhantomData;
use std::ops::Deref;

pub trait Inst: InstEncoding {
const META: &InstMeta;
Expand All @@ -15,6 +18,11 @@ pub trait Inst: InstEncoding {
}

pub trait InstEncoding: Sized + Debug + Eq {
/// Name of the instruction set, for debug printing
fn name() -> &'static str {
"unknown"
}

/// Encode this instruction to a [`WordWriter`]
fn encode(&self, writer: &mut impl WordWriter) -> Result<(), EncodeError>;

Expand Down Expand Up @@ -47,6 +55,26 @@ pub trait InstEncoding: Sized + Debug + Eq {
}
}

impl InstEncoding for () {
fn name() -> &'static str {
"()"
}

fn encode(&self, _: &mut impl WordWriter) -> Result<(), EncodeError> {
Ok(())
}

fn decode(reader: InstReader<'_>) -> Result<Self, DecodeError> {
Err(DecodeError::UnknownOpCode {
opcode: reader.opcode(),
})
}

fn dis_fmt(&self, _: &mut Formatter<'_>, _: &DisContext) -> std::fmt::Result {
Ok(())
}
}

pub struct InstDis<'a, T: InstEncoding>(&'a T, &'a DisContext);

impl<'a, T: InstEncoding> Display for InstDis<'a, T> {
Expand Down Expand Up @@ -92,3 +120,55 @@ impl MaybeIdResult for OptionIdResult {
pub fn make_mut_ref_unit() -> &'static mut () {
Box::leak(Box::new(()))
}

/// A reference to a valid instruction encoded in a slice of [`Word`]s.
///
/// Call [`Self::get`] to get the underlying instruction, as it unfortunately can't implement [`Deref`].
///
/// # Safety
/// The referenced words must be an encoded instruction that is valid within the `ISA` instruction set. Encountering an
/// invalid instruction may panic.
pub struct InstRef<'a, ISA: InstEncoding> {
reader: InstReader<'a>,
_phantom: PhantomData<ISA>,
}

impl<'a, ISA: InstEncoding> InstRef<'a, ISA> {
#[inline]
pub fn from_words_unchecked(words: &'a [Word]) -> Result<Self, DecodeError> {
Ok(Self {
reader: InstReader::from_words(words)?,
_phantom: PhantomData,
})
}

#[inline]
pub fn get(&self) -> ISA {
ISA::decode(**self).unwrap()
}
}

impl<'a, ISA: InstEncoding> Deref for InstRef<'a, ISA> {
type Target = InstReader<'a>;

#[inline]
fn deref(&self) -> &Self::Target {
&self.reader
}
}

impl<ISA: InstEncoding> Copy for InstRef<'_, ISA> {}

impl<ISA: InstEncoding> Clone for InstRef<'_, ISA> {
fn clone(&self) -> Self {
*self
}
}

impl<ISA: InstEncoding> Debug for InstRef<'_, ISA> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("InstRef")
.field("reader", &self.reader)
.finish()
}
}
2 changes: 2 additions & 0 deletions crates/rspirv2-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ pub mod inst;
pub mod meta;
pub mod module;
pub mod operand;
pub mod slice;
pub mod vec;
mod word;

pub use word::*;
Loading
Loading