Skip to content

Commit 335571a

Browse files
committed
spv: minimal OpSpecConstantOp support.
1 parent 219f924 commit 335571a

File tree

5 files changed

+95
-2
lines changed

5 files changed

+95
-2
lines changed

src/print/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1803,7 +1803,7 @@ impl Printer<'_> {
18031803
fn sanitize_spv_operand_name<'b>(&self, name: &'b str) -> Option<Cow<'b, str>> {
18041804
Some(name).and_then(|name| {
18051805
// HACK(eddyb) some operand names are useless.
1806-
if name == "Type"
1806+
if matches!(name, "Opcode" | "Operand" | "Type")
18071807
|| name
18081808
.strip_prefix("Operand ")
18091809
.is_some_and(|s| s.chars().all(|c| c.is_ascii_digit()))

src/spv/print.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ impl TokensForOperand<String> {
7777

7878
// FIXME(eddyb) keep a `&'static spec::Spec` if that can even speed up anything.
7979
struct OperandPrinter<IMMS: Iterator<Item = spv::Imm>, ID, IDS: Iterator<Item = ID>> {
80+
// FIXME(eddyb) use a field like this to interpret `Opcode`/`OperandKind`, too.
81+
wk: &'static spv::spec::WellKnown,
82+
8083
/// Input immediate operands to print from (may be grouped e.g. into literals).
8184
imms: iter::Peekable<IMMS>,
8285

@@ -123,7 +126,41 @@ impl<IMMS: Iterator<Item = spv::Imm>, ID, IDS: Iterator<Item = ID>> OperandPrint
123126
let def = kind.def();
124127
assert!(matches!(def, spec::OperandKindDef::Literal { .. }));
125128

126-
let literal_token = if kind == spec::Spec::get().well_known.LiteralString {
129+
let literal_token = if kind == self.wk.LiteralSpecConstantOpInteger {
130+
assert_eq!(words.len(), 1);
131+
let (_, inner_name, inner_def) = match u16::try_from(first_word)
132+
.ok()
133+
.and_then(spec::Opcode::try_from_u16_with_name_and_def)
134+
{
135+
Some(opcode_name_and_def) => opcode_name_and_def,
136+
None => {
137+
self.out.tokens.push(Token::Error(format!(
138+
"/* {first_word} not a valid `OpSpecConstantOp` opcode */"
139+
)));
140+
return;
141+
}
142+
};
143+
144+
// FIXME(eddyb) deduplicate this with `enumerant_params`.
145+
self.out.tokens.push(Token::EnumerandName(inner_name));
146+
147+
let mut first = true;
148+
for (inner_mode, inner_name_and_kind) in inner_def.all_operands_with_names() {
149+
if inner_mode == spec::OperandMode::Optional && self.is_exhausted() {
150+
break;
151+
}
152+
153+
self.out.tokens.push(Token::Punctuation(if first { "(" } else { ", " }));
154+
first = false;
155+
156+
let (inner_name, inner_kind) = inner_name_and_kind.name_and_kind();
157+
self.operand(inner_name, inner_kind);
158+
}
159+
if !first {
160+
self.out.tokens.push(Token::Punctuation(")"));
161+
}
162+
return;
163+
} else if kind == self.wk.LiteralString {
127164
// FIXME(eddyb) deduplicate with `spv::extract_literal_string`.
128165
let bytes: SmallVec<[u8; 64]> = words
129166
.into_iter()
@@ -260,6 +297,7 @@ impl<IMMS: Iterator<Item = spv::Imm>, ID, IDS: Iterator<Item = ID>> OperandPrint
260297
/// an enumerand with parameters (which consumes more immediates).
261298
pub fn operand_from_imms<T>(imms: impl IntoIterator<Item = spv::Imm>) -> TokensForOperand<T> {
262299
let mut printer = OperandPrinter {
300+
wk: &spec::Spec::get().well_known,
263301
imms: imms.into_iter().peekable(),
264302
ids: iter::empty().peekable(),
265303
out: TokensForOperand::default(),
@@ -282,6 +320,7 @@ pub fn inst_operands<ID>(
282320
ids: impl IntoIterator<Item = ID>,
283321
) -> impl Iterator<Item = TokensForOperand<ID>> {
284322
OperandPrinter {
323+
wk: &spec::Spec::get().well_known,
285324
imms: imms.into_iter().peekable(),
286325
ids: ids.into_iter().peekable(),
287326
out: TokensForOperand::default(),

src/spv/read.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ impl KnownIdDef {
2828

2929
// FIXME(eddyb) keep a `&'static spec::Spec` if that can even speed up anything.
3030
struct InstParser<'a> {
31+
// FIXME(eddyb) use a field like this to interpret `Opcode`/`OperandKind`, too.
32+
wk: &'static spv::spec::WellKnown,
33+
3134
/// IDs defined so far in the module.
3235
known_ids: &'a FxHashMap<spv::Id, KnownIdDef>,
3336

@@ -60,6 +63,9 @@ enum InstParseError {
6063
/// The type of a `LiteralContextDependentNumber` was not a supported type
6164
/// (one of either `OpTypeInt` or `OpTypeFloat`).
6265
UnsupportedContextSensitiveLiteralType { type_opcode: spec::Opcode },
66+
67+
/// Unsupported `OpSpecConstantOp` (`LiteralSpecConstantOpInteger`) opcode.
68+
UnsupportedSpecConstantOpOpcode(u32),
6369
}
6470

6571
impl InstParseError {
@@ -94,6 +100,9 @@ impl InstParseError {
94100
Self::UnsupportedContextSensitiveLiteralType { type_opcode } => {
95101
format!("{} is not a supported literal type", type_opcode.name()).into()
96102
}
103+
Self::UnsupportedSpecConstantOpOpcode(opcode) => {
104+
format!("{opcode} is not a supported opcode (for `OpSpecConstantOp`)").into()
105+
}
97106
}
98107
}
99108
}
@@ -198,6 +207,22 @@ impl InstParser<'_> {
198207
}
199208
}
200209

210+
// HACK(eddyb) this isn't cleanly uniform because it's an odd special case.
211+
if kind == self.wk.LiteralSpecConstantOpInteger {
212+
// FIXME(eddyb) this partially duplicates the main instruction parsing.
213+
let (_, _, inner_def) = u16::try_from(word)
214+
.ok()
215+
.and_then(spec::Opcode::try_from_u16_with_name_and_def)
216+
.ok_or(Error::UnsupportedSpecConstantOpOpcode(word))?;
217+
218+
for (inner_mode, inner_kind) in inner_def.all_operands() {
219+
if inner_mode == spec::OperandMode::Optional && self.is_exhausted() {
220+
break;
221+
}
222+
self.operand(inner_kind)?;
223+
}
224+
}
225+
201226
Ok(())
202227
}
203228

@@ -324,6 +349,7 @@ impl Iterator for ModuleParser {
324349
}
325350

326351
let parser = InstParser {
352+
wk: &spec::Spec::get().well_known,
327353
known_ids: &self.known_ids,
328354
words: words[1..inst_len].iter().copied(),
329355
inst: spv::InstWithIds {

src/spv/spec.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ def_well_known! {
183183
LiteralExtInstInteger,
184184
LiteralString,
185185
LiteralContextDependentNumber,
186+
LiteralSpecConstantOpInteger,
186187
],
187188
// FIXME(eddyb) find a way to namespace these to avoid conflicts.
188189
addressing_model: u32 = [

src/spv/write.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ use std::{fs, io, iter, slice};
77

88
// FIXME(eddyb) keep a `&'static spec::Spec` if that can even speed up anything.
99
struct OperandEmitter<'a> {
10+
// FIXME(eddyb) use a field like this to interpret `Opcode`/`OperandKind`, too.
11+
wk: &'static spv::spec::WellKnown,
12+
1013
/// Input immediate operands of an instruction.
1114
imms: iter::Copied<slice::Iter<'a, spv::Imm>>,
1215

@@ -32,6 +35,9 @@ enum OperandEmitError {
3235

3336
/// Unsupported enumerand value.
3437
UnsupportedEnumerand(spec::OperandKind, u32),
38+
39+
/// Unsupported `OpSpecConstantOp` (`LiteralSpecConstantOpInteger`) opcode.
40+
UnsupportedSpecConstantOpOpcode(u32),
3541
}
3642

3743
impl OperandEmitError {
@@ -60,6 +66,9 @@ impl OperandEmitError {
6066
_ => unreachable!(),
6167
}
6268
}
69+
Self::UnsupportedSpecConstantOpOpcode(opcode) => {
70+
format!("{opcode} is not a supported opcode (for `OpSpecConstantOp`)").into()
71+
}
6372
}
6473
}
6574
}
@@ -140,6 +149,23 @@ impl OperandEmitter<'_> {
140149
}
141150
}
142151

152+
// HACK(eddyb) this isn't cleanly uniform because it's an odd special case.
153+
if kind == self.wk.LiteralSpecConstantOpInteger {
154+
// FIXME(eddyb) this partially duplicates the main instruction emission.
155+
let &word = self.out.last().unwrap();
156+
let (_, _, inner_def) = u16::try_from(word)
157+
.ok()
158+
.and_then(spec::Opcode::try_from_u16_with_name_and_def)
159+
.ok_or(Error::UnsupportedSpecConstantOpOpcode(word))?;
160+
161+
for (inner_mode, inner_kind) in inner_def.all_operands() {
162+
if inner_mode == spec::OperandMode::Optional && self.is_exhausted() {
163+
break;
164+
}
165+
self.operand(inner_kind)?;
166+
}
167+
}
168+
143169
Ok(())
144170
}
145171

@@ -221,6 +247,7 @@ impl ModuleEmitter {
221247
);
222248

223249
OperandEmitter {
250+
wk: &spec::Spec::get().well_known,
224251
imms: inst.imms.iter().copied(),
225252
ids: inst.ids.iter().copied(),
226253
out: &mut self.words,

0 commit comments

Comments
 (0)