Skip to content

Commit 28f0bcc

Browse files
committed
Checkpoint
1 parent 236d9f8 commit 28f0bcc

File tree

12 files changed

+323
-60
lines changed

12 files changed

+323
-60
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rustc_codegen_spirv/src/link.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ fn do_spirv_opt(sess: &Session, spv_binary: Vec<u32>, filename: &Path) -> Vec<u3
187187
);
188188

189189
match result {
190-
Ok(binary) => binary.as_ref().to_vec(),
190+
Ok(binary) => Vec::from(binary.as_ref()),
191191
Err(_) => {
192192
let mut err = sess.struct_warn("spirv-opt failed, leaving as unoptimized");
193193
err.note(&format!("module {:?}", filename));
@@ -197,12 +197,11 @@ fn do_spirv_opt(sess: &Session, spv_binary: Vec<u32>, filename: &Path) -> Vec<u3
197197
}
198198

199199
fn do_spirv_val(sess: &Session, spv_binary: &[u32], filename: &Path) {
200-
use spirv_tools::{shared, val};
200+
use spirv_tools::val;
201201

202202
let validator = val::Validator::new(spirv_tools::TargetEnv::default());
203-
let opts = val::ValidatorOptions::default();
204203

205-
if validator.validate(spv_binary, &opts).is_err() {
204+
if validator.validate(spv_binary, None).is_err() {
206205
let mut err = sess.struct_err("error occurred during validation");
207206
err.note(&format!("module {:?}", filename));
208207
err.emit();

spirv-tools-sys/src/val.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ pub struct ValidatorOptions {
88
#[derive(Copy, Clone, Debug)]
99
#[repr(C)]
1010
pub enum ValidatorLimits {
11-
MaxStructMembers,
12-
MaxStructDepth,
13-
MaxLocalVariables,
14-
MaxGlobalVariables,
15-
MaxSwitchBranches,
16-
MaxFunctionArgs,
17-
MaxControlFlowNestingDepth,
18-
MaxAccessChainIndexes,
19-
MaxIdBound,
11+
StructMembers,
12+
StructDepth,
13+
LocalVariables,
14+
GlobalVariables,
15+
SwitchBranches,
16+
FunctionArgs,
17+
ControlFlowNestingDepth,
18+
AccessChainIndexes,
19+
IdBound,
2020
}
2121

2222
extern "C" {

spirv-tools/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ edition = "2018"
66
license = "MIT OR Apache-2.0"
77

88
[features]
9-
use-installed = ["spirv-tools-sys/use-installed"]
9+
use-installed = ["spirv-tools-sys/use-installed", "memchr"]
1010

1111
[dependencies]
1212
spirv-tools-sys = { path = "../spirv-tools-sys" }
13+
# Used for parsing output when running binaries
14+
memchr = { version = "2.3", optional = true }
1315

1416
[dev-dependencies]
1517
structopt = "0.3"

spirv-tools/src/assembler.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,21 @@ impl Assembler {
6060
if binary.is_null() {
6161
return Err(crate::error::Error {
6262
inner: shared::SpirvResult::InternalError,
63-
diagnostic: Some(crate::error::Diagnostic {
63+
diagnostics: vec![crate::error::Diagnostic {
6464
line: 0,
6565
column: 0,
6666
index: 0,
6767
message: "spirv assemble indicated success but did not return a valid binary".to_owned(),
6868
is_text: true,
69-
}),
69+
}],
7070
});
7171
}
7272

7373
Ok(crate::shared::Binary::new(binary))
7474
}
7575
other => Err(crate::error::Error {
7676
inner: other,
77-
diagnostic,
77+
diagnostics: vec![diagnostic],
7878
}),
7979
}
8080
}

spirv-tools/src/cmd.rs

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
use crate::error::Diagnostic;
2+
use std::process::{Command, Stdio};
3+
4+
pub enum CmdError {
5+
/// The binary failed to spawn, probably because it's not installed
6+
/// or not in PATH
7+
BinaryNotFound(std::io::Error),
8+
/// An I/O error occurred accessing the process' pipes
9+
Io(std::io::Error),
10+
/// The binary ran, but returned a non-zero exit code and (hopefully)
11+
/// diagnostics
12+
ToolErrors {
13+
exit_code: i32,
14+
/// Diagnostics that were parsed from the output
15+
diagnostics: Vec<Diagnostic>,
16+
},
17+
}
18+
19+
impl From<CmdError> for crate::error::Error {
20+
fn from(ce: CmdError) -> Self {}
21+
}
22+
23+
pub struct CmdOutput {
24+
/// The output the command is actually supposed to give back
25+
pub binary: Vec<u8>,
26+
/// Warning or Info level diagnostics that were gathered during execution
27+
pub diagnostics: Vec<Diagnostic>,
28+
}
29+
30+
#[derive(PartialEq, Copy, Clone)]
31+
pub enum Output {
32+
/// Doesn't try to read stdout for tool output (other than diagnostics)
33+
Ignore,
34+
/// Attempts to retrieve the tool's output from stdout
35+
Retrieve,
36+
}
37+
38+
pub fn exec(
39+
cmd: Command,
40+
input: Option<&[u8]>,
41+
retrieve_output: Output,
42+
) -> Result<CmdOutput, CmdError> {
43+
if input.is_some() {
44+
cmd.stdin(Stdio::piped());
45+
}
46+
47+
cmd.stdout(Stdio::piped()).stderr(Stdio::piped());
48+
49+
let mut child = cmd.spawn().map_err(|e| CmdError::BinaryNotFound(e))?;
50+
51+
if let Some(input) = input {
52+
use std::io::Write;
53+
54+
child
55+
.stdin
56+
.take()
57+
.unwrap()
58+
.write_all(input)
59+
.map_err(|e| CmdError::Io(e))?;
60+
}
61+
62+
let output = child.wait_with_output().map_err(|e| CmdError::Io(e))?;
63+
64+
let code = match output.status.code() {
65+
Some(code) => code,
66+
None => {
67+
#[cfg(unix)]
68+
let message = {
69+
use std::os::unix::process::ExitStatusExt;
70+
format!(
71+
"process terminated by signal: {}",
72+
output.status.signal().unwrap_or(666)
73+
)
74+
};
75+
#[cfg(not(unix))]
76+
let message = "process ended in an unknown state".to_owned();
77+
78+
return Err(CmdError::ToolErrors {
79+
exit_code: -1,
80+
diagnostics: vec![Diagnostic {
81+
line: 0,
82+
column: 0,
83+
index: 0,
84+
message,
85+
is_text: false,
86+
}],
87+
});
88+
}
89+
};
90+
91+
// stderr should only ever contain error+ level diagnostics
92+
if code != 0 {
93+
let diagnostics: Vec<_> = match String::from_utf8(output.stderr) {
94+
Ok(errors) => errors
95+
.lines()
96+
.filter_map(|line| crate::error::Message::parse(line).map(Diagnostic::from))
97+
.collect(),
98+
Err(e) => vec![Diagnostic {
99+
line: 0,
100+
column: 0,
101+
index: 0,
102+
message: format!(
103+
"unable to read stderr ({}) but process exited with code {}",
104+
e, code
105+
),
106+
is_text: false,
107+
}],
108+
};
109+
110+
return Err(CmdError::ToolErrors {
111+
exit_code: code,
112+
diagnostics,
113+
});
114+
}
115+
116+
fn split<'a>(haystack: &'a [u8], needle: u8) -> impl Iterator<Item = &'a [u8]> + 'a {
117+
struct Split<'a> {
118+
haystack: &'a [u8],
119+
needle: u8,
120+
}
121+
122+
impl<'a> Iterator for Split<'a> {
123+
type Item = &'a [u8];
124+
125+
fn next(&mut self) -> Option<&'a [u8]> {
126+
if self.haystack.is_empty() {
127+
return None;
128+
}
129+
let (ret, remaining) = match memchr::memchr(self.needle, self.haystack) {
130+
Some(pos) => (&self.haystack[..pos], &self.haystack[pos + 1..]),
131+
None => (self.haystack, &[][..]),
132+
};
133+
self.haystack = remaining;
134+
Some(ret)
135+
}
136+
}
137+
138+
Split { haystack, needle }
139+
}
140+
141+
let retrieve_output = retrieve_output == Output::Retrieve;
142+
143+
// Since we are retrieving the results via stdout, but it can also contain
144+
// diagnostic messages, we need to be careful
145+
let mut diagnostics = Vec::new();
146+
let mut binary = Vec::with_capacity(if retrieve_output { 1024 } else { 0 });
147+
148+
let mut iter = split(&output.stdout, b'\n');
149+
let mut maybe_diagnostic = true;
150+
for line in iter {
151+
if maybe_diagnostic {
152+
if let Some(s) = std::str::from_utf8(line).ok() {
153+
if let Some(msg) = crate::error::Message::parse(s) {
154+
diagnostics.push(Diagnostic::from(msg));
155+
continue;
156+
}
157+
}
158+
}
159+
160+
if retrieve_output {
161+
binary.extend_from_slice(line);
162+
}
163+
maybe_diagnostic = false;
164+
}
165+
166+
Ok(CmdOutput {
167+
binary,
168+
diagnostics,
169+
})
170+
}

spirv-tools/src/error.rs

+46-25
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,25 @@ pub use diagnostics::MessageLevel;
55
#[derive(Debug, PartialEq)]
66
pub struct Error {
77
pub inner: shared::SpirvResult,
8-
pub diagnostic: Option<Diagnostic>,
8+
pub diagnostics: Vec<Diagnostic>,
99
}
1010

1111
use std::fmt;
1212

1313
impl fmt::Display for Error {
1414
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15-
match &self.diagnostic {
16-
Some(diag) => f.write_fmt(format_args!(
17-
"{}:{}:{} - {}",
18-
self.inner, diag.line, diag.column, diag.message
19-
)),
20-
None => f.write_fmt(format_args!("{}", self.inner)),
15+
f.write_fmt(format_args!("{}", self.inner))?;
16+
17+
if !self.diagnostics.is_empty() {
18+
for diag in &self.diagnostics {
19+
f.write_fmt(format_args!(
20+
"\n{}:{}:{} - {}",
21+
self.inner, diag.line, diag.column, diag.message
22+
))?
23+
}
2124
}
25+
26+
Ok(())
2227
}
2328
}
2429

@@ -65,6 +70,18 @@ impl std::convert::TryFrom<*mut diagnostics::Diagnostic> for Diagnostic {
6570
}
6671
}
6772

73+
impl<'a> From<Message<'a>> for Diagnostic {
74+
fn from(msg: Message<'a>) -> Self {
75+
Self {
76+
line: msg.line,
77+
column: msg.column,
78+
index: msg.index,
79+
message: msg.message.to_string(),
80+
is_text: false,
81+
}
82+
}
83+
}
84+
6885
pub struct Message<'a> {
6986
pub level: MessageLevel,
7087
pub source: std::borrow::Cow<'a, str>,
@@ -108,31 +125,35 @@ impl<'a> Message<'a> {
108125

109126
pub(crate) fn parse(s: &'a str) -> Option<Self> {
110127
s.find(": ")
111-
.and_then(|i| {
112-
let level = match &s[..i] {
113-
"error" => MessageLevel::Error,
114-
"warning" => MessageLevel::Warning,
115-
"info" => MessageLevel::Info,
116-
_ => return None,
117-
};
118-
119-
Some((level, i))
120-
}).and_then(|(level, i)| {
121-
s[i + 7..].find(": ").and_then(|i2| {
122-
s[i + 7..i + 7 + i2].parse::<usize>().ok().map(|index| (index, i2))
123-
}).map(|(index, i2)| {
124-
(level, index, i + 7 + i2 + 2)
128+
.and_then(|i| {
129+
let level = match &s[..i] {
130+
"error" => MessageLevel::Error,
131+
"warning" => MessageLevel::Warning,
132+
"info" => MessageLevel::Info,
133+
_ => return None,
134+
};
135+
136+
Some((level, i))
125137
})
126-
}).map(|(level, index, last)| {
127-
Self {
138+
.and_then(|(level, i)| {
139+
s[i + 7..]
140+
.find(": ")
141+
.and_then(|i2| {
142+
s[i + 7..i + 7 + i2]
143+
.parse::<usize>()
144+
.ok()
145+
.map(|index| (index, i2))
146+
})
147+
.map(|(index, i2)| (level, index, i + 7 + i2 + 2))
148+
})
149+
.map(|(level, index, last)| Self {
128150
level,
129151
index,
130152
message: std::borrow::Cow::Borrowed(&s[last..]),
131153
source: std::borrow::Cow::Borrowed(""),
132154
line: 0,
133155
column: 0,
134-
}
135-
})
156+
})
136157
}
137158
}
138159

spirv-tools/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@ pub mod error;
77
pub use error::Error;
88

99
pub use spirv_tools_sys::shared::TargetEnv;
10+
11+
#[cfg(feature = "use-installed")]
12+
pub(crate) mod cmd;
13+
14+
pub mod util;

0 commit comments

Comments
 (0)