Skip to content

Commit 9ee7f75

Browse files
alexcrichtongnzlbg
authored andcommitted
Fix verifying instructions for MIPS
Looks like MIPS is the first architecture to have verification which exercises the more flavorful forms of `assert_instr`, so the parsing code for `assert_instr` needed an update. Closes #713
1 parent 2035117 commit 9ee7f75

File tree

2 files changed

+52
-30
lines changed

2 files changed

+52
-30
lines changed

crates/stdsimd-verify/src/lib.rs

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ extern crate quote;
55
#[macro_use]
66
extern crate syn;
77

8+
use proc_macro::TokenStream;
9+
use proc_macro2::Span;
810
use std::fs::File;
911
use std::io::Read;
1012
use std::path::Path;
11-
12-
use proc_macro::TokenStream;
13+
use syn::ext::IdentExt;
1314

1415
#[proc_macro]
1516
pub fn x86_functions(input: TokenStream) -> TokenStream {
@@ -91,7 +92,7 @@ fn functions(input: TokenStream, dirs: &[&str]) -> TokenStream {
9192
arguments: &[#(#arguments),*],
9293
ret: #ret,
9394
target_feature: #target_feature,
94-
instrs: &[#(stringify!(#instrs)),*],
95+
instrs: &[#(#instrs),*],
9596
file: stringify!(#path),
9697
required_const: &[#(#required_const),*],
9798
}
@@ -263,35 +264,54 @@ fn walk(root: &Path, files: &mut Vec<(syn::File, String)>) {
263264
}
264265
}
265266

266-
fn find_instrs(attrs: &[syn::Attribute]) -> Vec<syn::Ident> {
267-
attrs
267+
fn find_instrs(attrs: &[syn::Attribute]) -> Vec<String> {
268+
return attrs
268269
.iter()
269-
.filter_map(|a| a.interpret_meta())
270-
.filter_map(|a| match a {
271-
syn::Meta::List(i) => {
272-
if i.ident == "cfg_attr" {
273-
i.nested.into_iter().nth(1)
274-
} else {
275-
None
276-
}
270+
.filter(|a| a.path == syn::Ident::new("cfg_attr", Span::call_site()).into())
271+
.filter_map(|a| syn::parse2::<AssertInstr>(a.tts.clone()).ok())
272+
.map(|a| a.instr)
273+
.collect();
274+
275+
struct AssertInstr {
276+
instr: String,
277+
}
278+
279+
// A small custom parser to parse out the instruction in `assert_instr`.
280+
//
281+
// TODO: should probably just reuse `Invoc` from the `assert-instr-macro`
282+
// crate.
283+
impl syn::parse::Parse for AssertInstr {
284+
fn parse(content: syn::parse::ParseStream) -> syn::parse::Result<Self> {
285+
let input;
286+
parenthesized!(input in content);
287+
drop(input.parse::<syn::Meta>()?);
288+
drop(input.parse::<Token![,]>()?);
289+
let ident = input.parse::<syn::Ident>()?;
290+
if ident != "assert_instr" {
291+
return Err(input.error("expected `assert_instr`"));
277292
}
278-
_ => None,
279-
})
280-
.filter_map(|nested| match nested {
281-
syn::NestedMeta::Meta(syn::Meta::List(i)) => {
282-
if i.ident == "assert_instr" {
283-
i.nested.into_iter().next()
293+
let instrs;
294+
parenthesized!(instrs in input);
295+
296+
let mut instr = String::new();
297+
while !instrs.is_empty() {
298+
if let Ok(lit) = instrs.parse::<syn::LitStr>() {
299+
instr.push_str(&lit.value());
300+
} else if let Ok(ident) = instrs.call(syn::Ident::parse_any) {
301+
instr.push_str(&ident.to_string());
302+
} else if instrs.parse::<Token![.]>().is_ok() {
303+
instr.push_str(".");
304+
} else if instrs.parse::<Token![,]>().is_ok() {
305+
// consume everything remaining
306+
drop(instrs.parse::<proc_macro2::TokenStream>());
307+
break;
284308
} else {
285-
None
309+
return Err(input.error("failed to parse instruction"));
286310
}
287311
}
288-
_ => None,
289-
})
290-
.filter_map(|nested| match nested {
291-
syn::NestedMeta::Meta(syn::Meta::Word(i)) => Some(i),
292-
_ => None,
293-
})
294-
.collect()
312+
Ok(AssertInstr { instr })
313+
}
314+
}
295315
}
296316

297317
fn find_target_feature(attrs: &[syn::Attribute]) -> Option<syn::Lit> {

crates/stdsimd-verify/tests/mips.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,16 +313,18 @@ fn matches(rust: &Function, mips: &MsaIntrinsic) -> Result<(), String> {
313313
bail!("wrong target_feature");
314314
}
315315

316-
/* FIXME:
317316
if !rust.instrs.is_empty() {
318-
if rust.instrs[0] != mips.instruction {
317+
// Normalize slightly to get rid of assembler differences
318+
let actual = rust.instrs[0].replace(".", "_");
319+
let expected = mips.instruction.replace(".", "_");
320+
if actual != expected {
319321
bail!("wrong instruction: \"{}\" != \"{}\"", rust.instrs[0], mips.instruction);
320322
}
321323
} else {
322324
bail!(
323325
"missing assert_instr for \"{}\" (should be \"{}\")",
324326
mips.id, mips.instruction);
325-
}*/
327+
}
326328

327329
Ok(())
328330
}

0 commit comments

Comments
 (0)