use lazy_static::lazy_static;
use rspirv::dr::{Instruction, Operand};
use rspirv::spirv::Op;
use smallvec::SmallVec;
pub const CUSTOM_EXT_INST_SET_PREFIX: &str = concat!("Rust.", env!("CARGO_PKG_NAME"), ".");
lazy_static! {
pub static ref CUSTOM_EXT_INST_SET: String = {
const VER_MAJOR: &str = env!("CARGO_PKG_VERSION_MAJOR");
const VER_MINOR: &str = env!("CARGO_PKG_VERSION_MINOR");
const VER_PATCH: &str = env!("CARGO_PKG_VERSION_PATCH");
let schema_hash = {
use rustc_data_structures::stable_hasher::StableHasher;
use std::hash::Hash;
let mut hasher = StableHasher::new();
SCHEMA.hash(&mut hasher);
let (lo, hi) = hasher.finalize();
(lo as u128) | ((hi as u128) << 64)
};
format!("{CUSTOM_EXT_INST_SET_PREFIX}{VER_MAJOR}_{VER_MINOR}_{VER_PATCH}.{schema_hash:x}")
};
}
macro_rules! def_custom_insts {
($($num:literal => $name:ident $({ $($field:ident),+ $(,)? })?),+ $(,)?) => {
const SCHEMA: &[(u32, &str, &[&str])] = &[
$(($num, stringify!($name), &[$($(stringify!($field)),+)?])),+
];
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum CustomOp { $($name = $num),+ }
impl CustomOp {
pub fn decode(i: u32) -> Self {
match i {
$($num => Self::$name,)+
_ => unreachable!("{i} is not a valid custom instruction number"),
}
}
pub fn decode_from_ext_inst(inst: &Instruction) -> Self {
assert_eq!(inst.class.opcode, Op::ExtInst);
Self::decode(inst.operands[1].unwrap_literal_ext_inst_integer())
}
pub fn with_operands<T: Clone>(self, operands: &[T]) -> CustomInst<T> {
match self {
$(Self::$name => match operands {
[$($($field),+)?] => CustomInst::$name $({ $($field: $field.clone()),+ })?,
_ => unreachable!("{self:?} does not have the right number of operands"),
}),+
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum CustomInst<T> {
$($name $({ $($field: T),+ })?),+
}
impl<T> CustomInst<T> {
pub fn op(&self) -> CustomOp {
match *self {
$(Self::$name { .. } => CustomOp::$name),+
}
}
pub fn into_operands(self) -> SmallVec<[T; 8]> {
match self {
$(Self::$name $({ $($field),+ })? => [$($($field),+)?].into_iter().collect()),+
}
}
}
impl CustomInst<Operand> {
pub fn decode(inst: &Instruction) -> Self {
CustomOp::decode_from_ext_inst(inst).with_operands(&inst.operands[2..])
}
}
}
}
def_custom_insts! {
0 => SetDebugSrcLoc { file, line_start, line_end, col_start, col_end },
1 => ClearDebugSrcLoc,
2 => PushInlinedCallFrame { callee_name },
3 => PopInlinedCallFrame,
}