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
78 changes: 77 additions & 1 deletion crates/autogen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,19 @@ pub fn main() -> anyhow::Result<()> {
pub fn autogen() -> anyhow::Result<()> {
let core_json = PATH_GRAMMAR_CORE.read()?;
let mut core = core_json.parse_grammar()?;

// instructions that require custom implementations
core.insts
.iter_mut()
.filter(|i| i.opname == "OpSwitch")
.filter(|i| i.opname == "OpSwitch" || i.opname == "OpSpecConstantOp")
.for_each(|i| i.source = Source::MetaOnly);

// mark instructions as OpSpecOp
core.insts
.iter_mut()
.filter(|i| OP_SPEC_OP_NAMES.contains(&&*i.opname))
.for_each(|i| i.op_spec_op = true);

write_grammar(
GrammarWriter::new(Path::new(PATH_GRAMMAR_CRATE_SRC).join("core"))?,
&core,
Expand All @@ -29,3 +38,70 @@ pub fn autogen() -> anyhow::Result<()> {
)?;
Ok(())
}

/// All instructions that are allowed in `OpSpecConstantOp`, see List at
/// <https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpSpecConstantOp>
///
/// List is not yet machine parsable, see <https://github.com/KhronosGroup/SPIRV-Headers/issues/645>
const OP_SPEC_OP_NAMES: &[&str] = &[
"OpSConvert",
"OpUConvert",
"OpFConvert",
"OpSNegate",
"OpNot",
"OpIAdd",
"OpISub",
"OpIMul",
"OpUDiv",
"OpSDiv",
"OpUMod",
"OpSRem",
"OpSMod",
"OpShiftRightLogical",
"OpShiftRightArithmetic",
"OpShiftLeftLogical",
"OpBitwiseOr",
"OpBitwiseXor",
"OpBitwiseAnd",
"OpVectorShuffle",
"OpCompositeExtract",
"OpCompositeInsert",
"OpLogicalOr",
"OpLogicalAnd",
"OpLogicalNot",
"OpLogicalEqual",
"OpLogicalNotEqual",
"OpSelect",
"OpIEqual",
"OpINotEqual",
"OpULessThan",
"OpSLessThan",
"OpUGreaterThan",
"OpSGreaterThan",
"OpULessThanEqual",
"OpSLessThanEqual",
"OpUGreaterThanEqual",
"OpSGreaterThanEqual",
"OpQuantizeToF16",
"OpConvertFToS",
"OpConvertSToF",
"OpConvertFToU",
"OpConvertUToF",
"OpUConvert",
"OpConvertPtrToU",
"OpConvertUToPtr",
"OpGenericCastToPtr",
"OpPtrCastToGeneric",
"OpBitcast",
"OpFNegate",
"OpFAdd",
"OpFSub",
"OpFMul",
"OpFDiv",
"OpFRem",
"OpFMod",
"OpAccessChain",
"OpInBoundsAccessChain",
"OpPtrAccessChain",
"OpInBoundsPtrAccessChain",
];
93 changes: 83 additions & 10 deletions crates/grammar-parser/src/codegen/inst.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use crate::codegen::{GrammarWriter, OPERAND_ID_RESULT, OPERAND_ID_RESULT_TYPE};
use crate::parse::{Grammar, InstMeta, Operand, Quantifier};
use anyhow::Context;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};

pub fn write_inst(writer: &mut GrammarWriter, grammar: &Grammar<'_>) -> anyhow::Result<()> {
let insts = grammar.insts.iter().map(|inst| {
let struct_ident = InstMeta::type_ident(&inst.opname);
if !inst.source.codegen_impl() {
return quote!(pub use super::preamble::#struct_ident;);
return Ok(quote!(pub use super::preamble::#struct_ident;));
}

let meta = InstMeta::const_ident(&inst.opname);
Expand Down Expand Up @@ -53,6 +55,80 @@ pub fn write_inst(writer: &mut GrammarWriter, grammar: &Grammar<'_>) -> anyhow::
(quote!(()), quote!())
};

// OpSpecOp
let op_spec_op_encoding = if inst.op_spec_op {
let missing_operands = || {
format!("Instruction {} is marked as `op_spec_op` compatible but doesn't have required `IdResult` and \
`IdResultType` operands. All operands: {:?}", inst.opname, inst.operands)
};
let id_result = id_result.with_context(missing_operands)?;
let id_result_type = id_result_type.with_context(missing_operands)?;

// members that are not IdResult or IdResultType, since those need special casing.
let member_operands = member_operands
.iter()
.filter(|&op| {
!core::ptr::eq(op, id_result)
&& !core::ptr::eq(op, id_result_type)
})
.collect::<Vec<_>>();
let members = member_operands
.iter()
.map(|Operand { name, .. }| name)
.collect::<Vec<_>>();
let members_non_last = &members[..members.len().saturating_sub(1)];
let members_last = members.last().into_iter();
let member_id_result = &id_result.name;
let member_id_result_type = &id_result_type.name;

// disassembly
let dis_operands_value = member_operands
.iter()
.map(|op| {
let name = &op.name;
quote!(, self.#name.dis(ctx))
})
.collect::<Vec<_>>();
let pat = [inst.opname.as_ref()]
.into_iter()
.chain(member_operands.iter().map(|_| "{}"))
.collect::<String>();

quote! {
impl OpSpecOpInst for #struct_ident {
fn op_spec_op_encode(&self, writer: &mut impl WordWriter) -> Result<(), EncodeError> {
profiling::function_scope!();
OperandEncoding::encode(&self.#member_id_result_type, &mut *writer)?;
OperandEncoding::encode(&self.#member_id_result, &mut *writer)?;
writer.write_op(Self::META.opcode, 0)?;
#(OperandEncoding::encode(&self.#members, &mut *writer)?;)*
Ok(())
}

fn op_spec_op_decode(reader: &[Word]) -> Result<Self, DecodeError> {
profiling::function_scope!();
let mut op_reader = OperandReader::new(reader);
let #member_id_result_type = OperandEncoding::decode(&mut op_reader)?;
let #member_id_result = OperandEncoding::decode(&mut op_reader)?;
op_reader.pull_expected_opcode(Self::META)?;
Ok(Self {
#member_id_result_type,
#member_id_result,
#(#members_non_last: OperandEncoding::decode(&mut op_reader)?,)*
#(#members_last: OperandEncoding::decode_last(&mut op_reader)?,)*
})
}

fn op_spec_op_dis_fmt(&self, f: &mut Formatter<'_>, ctx: OperandDisContext<'_>) -> std::fmt::Result {
profiling::function_scope!();
write!(f, #pat #(#dis_operands_value)*)
}
}
}
} else {
quote!()
};

// encode decode
let members = member_operands
.iter()
Expand Down Expand Up @@ -133,7 +209,7 @@ pub fn write_inst(writer: &mut GrammarWriter, grammar: &Grammar<'_>) -> anyhow::
}
};

quote! {
Ok(quote! {
#struct_def
#(#aliases)*

Expand Down Expand Up @@ -177,12 +253,9 @@ pub fn write_inst(writer: &mut GrammarWriter, grammar: &Grammar<'_>) -> anyhow::
write!(f, #pat, ctx.id_result_writer() #(#dis_operands_value)*)
}
}
}
});
writer.write_module(
"inst",
quote! {
#(#insts)*
},
)

#op_spec_op_encoding
})
}).collect::<anyhow::Result<TokenStream>>()?;
writer.write_module("inst", insts)
}
Loading
Loading