Upgrade to rustfmt 0.8.0.
Lots of changes this time. Worked around what looks like a rustfmt bug in parse_inst_operands where a large match was nested inside Ok().
This commit is contained in:
@@ -51,11 +51,7 @@ pub type CommandResult = Result<(), String>;
|
|||||||
fn cton_util() -> CommandResult {
|
fn cton_util() -> CommandResult {
|
||||||
// Parse comand line arguments.
|
// Parse comand line arguments.
|
||||||
let args: Args = Docopt::new(USAGE)
|
let args: Args = Docopt::new(USAGE)
|
||||||
.and_then(|d| {
|
.and_then(|d| d.help(true).version(Some(format!("Cretonne {}", VERSION))).decode())
|
||||||
d.help(true)
|
|
||||||
.version(Some(format!("Cretonne {}", VERSION)))
|
|
||||||
.decode()
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|e| e.exit());
|
.unwrap_or_else(|e| e.exit());
|
||||||
|
|
||||||
// Find the sub-command to execute.
|
// Find the sub-command to execute.
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ fn heartbeat_thread(replies: Sender<Reply>) -> thread::JoinHandle<()> {
|
|||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name("heartbeat".to_string())
|
.name("heartbeat".to_string())
|
||||||
.spawn(move || while replies.send(Reply::Tick).is_ok() {
|
.spawn(move || while replies.send(Reply::Tick).is_ok() {
|
||||||
thread::sleep(Duration::from_secs(1));
|
thread::sleep(Duration::from_secs(1));
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,9 +120,9 @@ fn worker_thread(thread_num: usize,
|
|||||||
// Tell them we're starting this job.
|
// Tell them we're starting this job.
|
||||||
// The receiver should always be present for this as long as we have jobs.
|
// The receiver should always be present for this as long as we have jobs.
|
||||||
replies.send(Reply::Starting {
|
replies.send(Reply::Starting {
|
||||||
jobid: jobid,
|
jobid: jobid,
|
||||||
thread_num: thread_num,
|
thread_num: thread_num,
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = catch_unwind(|| runone::run(path.as_path())).unwrap_or_else(|e| {
|
let result = catch_unwind(|| runone::run(path.as_path())).unwrap_or_else(|e| {
|
||||||
@@ -138,9 +138,9 @@ fn worker_thread(thread_num: usize,
|
|||||||
});
|
});
|
||||||
|
|
||||||
replies.send(Reply::Done {
|
replies.send(Reply::Done {
|
||||||
jobid: jobid,
|
jobid: jobid,
|
||||||
result: result,
|
result: result,
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -89,7 +89,10 @@ impl SubTest for TestDomtree {
|
|||||||
|
|
||||||
// Now we know that everything in `expected` is consistent with `domtree`.
|
// Now we know that everything in `expected` is consistent with `domtree`.
|
||||||
// All other EBB's should be either unreachable or the entry block.
|
// All other EBB's should be either unreachable or the entry block.
|
||||||
for ebb in func.layout.ebbs().skip(1).filter(|ebb| !expected.contains_key(&ebb)) {
|
for ebb in func.layout
|
||||||
|
.ebbs()
|
||||||
|
.skip(1)
|
||||||
|
.filter(|ebb| !expected.contains_key(&ebb)) {
|
||||||
if let Some(got_inst) = domtree.idom(ebb) {
|
if let Some(got_inst) = domtree.idom(ebb) {
|
||||||
return Err(format!("mismatching idoms for renumbered {}:\n\
|
return Err(format!("mismatching idoms for renumbered {}:\n\
|
||||||
want: unrechable, got: {}",
|
want: unrechable, got: {}",
|
||||||
|
|||||||
@@ -105,9 +105,9 @@ impl TestRunner {
|
|||||||
/// Any problems reading `file` as a test case file will be reported as a test failure.
|
/// Any problems reading `file` as a test case file will be reported as a test failure.
|
||||||
pub fn push_test<P: Into<PathBuf>>(&mut self, file: P) {
|
pub fn push_test<P: Into<PathBuf>>(&mut self, file: P) {
|
||||||
self.tests.push(QueueEntry {
|
self.tests.push(QueueEntry {
|
||||||
path: file.into(),
|
path: file.into(),
|
||||||
state: State::New,
|
state: State::New,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Begin running tests concurrently.
|
/// Begin running tests concurrently.
|
||||||
@@ -277,9 +277,9 @@ impl TestRunner {
|
|||||||
let mut times = self.tests
|
let mut times = self.tests
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|entry| match *entry {
|
.filter_map(|entry| match *entry {
|
||||||
QueueEntry { state: State::Done(Ok(dur)), .. } => Some(dur),
|
QueueEntry { state: State::Done(Ok(dur)), .. } => Some(dur),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Get me some real data, kid.
|
// Get me some real data, kid.
|
||||||
@@ -303,12 +303,12 @@ impl TestRunner {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for t in self.tests
|
for t in self.tests.iter().filter(|entry| match **entry {
|
||||||
.iter()
|
QueueEntry { state: State::Done(Ok(dur)), .. } => {
|
||||||
.filter(|entry| match **entry {
|
dur > cut
|
||||||
QueueEntry { state: State::Done(Ok(dur)), .. } => dur > cut,
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}) {
|
}) {
|
||||||
println!("slow: {}", t)
|
println!("slow: {}", t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ pub fn run(path: &Path) -> TestResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse the test commands.
|
// Parse the test commands.
|
||||||
let mut tests = testfile.commands.iter().map(new_subtest).collect::<Result<Vec<_>>>()?;
|
let mut tests = testfile.commands
|
||||||
|
.iter()
|
||||||
|
.map(new_subtest)
|
||||||
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
// Flags to use for those tests that don't need an ISA.
|
// Flags to use for those tests that don't need an ISA.
|
||||||
// This is the cumulative effect of all the `set` commands in the file.
|
// This is the cumulative effect of all the `set` commands in the file.
|
||||||
|
|||||||
@@ -66,7 +66,10 @@ pub trait SubTest {
|
|||||||
/// match 'inst10'.
|
/// match 'inst10'.
|
||||||
impl<'a> filecheck::VariableMap for Context<'a> {
|
impl<'a> filecheck::VariableMap for Context<'a> {
|
||||||
fn lookup(&self, varname: &str) -> Option<FCValue> {
|
fn lookup(&self, varname: &str) -> Option<FCValue> {
|
||||||
self.details.map.lookup_str(varname).map(|e| FCValue::Regex(format!(r"\b{}\b", e).into()))
|
self.details
|
||||||
|
.map
|
||||||
|
.lookup_str(varname)
|
||||||
|
.map(|e| FCValue::Regex(format!(r"\b{}\b", e).into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,8 +80,7 @@ pub fn run_filecheck(text: &str, context: &Context) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
// Filecheck mismatch. Emit an explanation as output.
|
// Filecheck mismatch. Emit an explanation as output.
|
||||||
let (_, explain) = checker.explain(&text, context)
|
let (_, explain) = checker.explain(&text, context).map_err(|e| format!("explain: {}", e))?;
|
||||||
.map_err(|e| format!("explain: {}", e))?;
|
|
||||||
Err(format!("filecheck failed:\n{}{}", checker, explain))
|
Err(format!("filecheck failed:\n{}{}", checker, explain))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ pub fn run(files: Vec<String>, verbose: bool) -> CommandResult {
|
|||||||
io::stdin().read_to_string(&mut buffer).map_err(|e| format!("stdin: {}", e))?;
|
io::stdin().read_to_string(&mut buffer).map_err(|e| format!("stdin: {}", e))?;
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
let (success, explain) = checker.explain(&buffer, NO_VARIABLES)
|
let (success, explain) = checker.explain(&buffer, NO_VARIABLES).map_err(|e| e.to_string())?;
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
print!("{}", explain);
|
print!("{}", explain);
|
||||||
if success {
|
if success {
|
||||||
println!("OK");
|
println!("OK");
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ function banner() {
|
|||||||
# rustfmt is installed.
|
# rustfmt is installed.
|
||||||
#
|
#
|
||||||
# This version should always be bumped to the newest version available.
|
# This version should always be bumped to the newest version available.
|
||||||
RUSTFMT_VERSION="0.7.1"
|
RUSTFMT_VERSION="0.8.0"
|
||||||
|
|
||||||
if cargo install --list | grep -q "^rustfmt v$RUSTFMT_VERSION"; then
|
if cargo install --list | grep -q "^rustfmt v$RUSTFMT_VERSION"; then
|
||||||
banner "Rust formatting"
|
banner "Rust formatting"
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ use self::cretonne::entity_map::EntityMap;
|
|||||||
fn test_reverse_postorder_traversal(function_source: &str, ebb_order: Vec<u32>) {
|
fn test_reverse_postorder_traversal(function_source: &str, ebb_order: Vec<u32>) {
|
||||||
let func = &parse_functions(function_source).unwrap()[0];
|
let func = &parse_functions(function_source).unwrap()[0];
|
||||||
let cfg = ControlFlowGraph::with_function(&func);
|
let cfg = ControlFlowGraph::with_function(&func);
|
||||||
let ebbs = ebb_order.iter()
|
let ebbs = ebb_order.iter().map(|n| Ebb::with_number(*n).unwrap()).collect::<Vec<Ebb>>();
|
||||||
.map(|n| Ebb::with_number(*n).unwrap())
|
|
||||||
.collect::<Vec<Ebb>>();
|
|
||||||
|
|
||||||
let mut postorder_ebbs = cfg.postorder_ebbs();
|
let mut postorder_ebbs = cfg.postorder_ebbs();
|
||||||
let mut postorder_map = EntityMap::with_capacity(postorder_ebbs.len());
|
let mut postorder_map = EntityMap::with_capacity(postorder_ebbs.len());
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ fn main() {
|
|||||||
// Make sure we rebuild is this build script changes.
|
// Make sure we rebuild is this build script changes.
|
||||||
// I guess that won't happen if you have non-UTF8 bytes in your path names.
|
// I guess that won't happen if you have non-UTF8 bytes in your path names.
|
||||||
// The `build.py` script prints out its own dependencies.
|
// The `build.py` script prints out its own dependencies.
|
||||||
println!("cargo:rerun-if-changed={}", crate_dir.join("build.rs").to_string_lossy());
|
println!("cargo:rerun-if-changed={}",
|
||||||
|
crate_dir.join("build.rs").to_string_lossy());
|
||||||
|
|
||||||
// Scripts are in `$crate_dir/meta`.
|
// Scripts are in `$crate_dir/meta`.
|
||||||
let meta_dir = crate_dir.join("meta");
|
let meta_dir = crate_dir.join("meta");
|
||||||
|
|||||||
@@ -191,12 +191,14 @@ impl DominatorTree {
|
|||||||
// Get an iterator with just the reachable predecessors to `ebb`.
|
// Get an iterator with just the reachable predecessors to `ebb`.
|
||||||
// Note that during the first pass, `is_reachable` returns false for blocks that haven't
|
// Note that during the first pass, `is_reachable` returns false for blocks that haven't
|
||||||
// been visited yet.
|
// been visited yet.
|
||||||
let mut reachable_preds =
|
let mut reachable_preds = cfg.get_predecessors(ebb)
|
||||||
cfg.get_predecessors(ebb).iter().cloned().filter(|&(ebb, _)| self.is_reachable(ebb));
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.filter(|&(ebb, _)| self.is_reachable(ebb));
|
||||||
|
|
||||||
// The RPO must visit at least one predecessor before this node.
|
// The RPO must visit at least one predecessor before this node.
|
||||||
let mut idom = reachable_preds.next()
|
let mut idom =
|
||||||
.expect("EBB node must have one reachable predecessor");
|
reachable_preds.next().expect("EBB node must have one reachable predecessor");
|
||||||
|
|
||||||
for pred in reachable_preds {
|
for pred in reachable_preds {
|
||||||
idom = self.common_dominator(idom, pred, layout);
|
idom = self.common_dominator(idom, pred, layout);
|
||||||
|
|||||||
@@ -89,17 +89,17 @@ impl Display for IntCC {
|
|||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
use self::IntCC::*;
|
use self::IntCC::*;
|
||||||
f.write_str(match self {
|
f.write_str(match self {
|
||||||
&Equal => "eq",
|
&Equal => "eq",
|
||||||
&NotEqual => "ne",
|
&NotEqual => "ne",
|
||||||
&SignedGreaterThan => "sgt",
|
&SignedGreaterThan => "sgt",
|
||||||
&SignedGreaterThanOrEqual => "sge",
|
&SignedGreaterThanOrEqual => "sge",
|
||||||
&SignedLessThan => "slt",
|
&SignedLessThan => "slt",
|
||||||
&SignedLessThanOrEqual => "sle",
|
&SignedLessThanOrEqual => "sle",
|
||||||
&UnsignedGreaterThan => "ugt",
|
&UnsignedGreaterThan => "ugt",
|
||||||
&UnsignedGreaterThanOrEqual => "uge",
|
&UnsignedGreaterThanOrEqual => "uge",
|
||||||
&UnsignedLessThan => "ult",
|
&UnsignedLessThan => "ult",
|
||||||
&UnsignedLessThanOrEqual => "ule",
|
&UnsignedLessThanOrEqual => "ule",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,21 +220,21 @@ impl Display for FloatCC {
|
|||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
use self::FloatCC::*;
|
use self::FloatCC::*;
|
||||||
f.write_str(match self {
|
f.write_str(match self {
|
||||||
&Ordered => "ord",
|
&Ordered => "ord",
|
||||||
&Unordered => "uno",
|
&Unordered => "uno",
|
||||||
&Equal => "eq",
|
&Equal => "eq",
|
||||||
&NotEqual => "ne",
|
&NotEqual => "ne",
|
||||||
&OrderedNotEqual => "one",
|
&OrderedNotEqual => "one",
|
||||||
&UnorderedOrEqual => "ueq",
|
&UnorderedOrEqual => "ueq",
|
||||||
&LessThan => "lt",
|
&LessThan => "lt",
|
||||||
&LessThanOrEqual => "le",
|
&LessThanOrEqual => "le",
|
||||||
&GreaterThan => "gt",
|
&GreaterThan => "gt",
|
||||||
&GreaterThanOrEqual => "ge",
|
&GreaterThanOrEqual => "ge",
|
||||||
&UnorderedOrLessThan => "ult",
|
&UnorderedOrLessThan => "ult",
|
||||||
&UnorderedOrLessThanOrEqual => "ule",
|
&UnorderedOrLessThanOrEqual => "ule",
|
||||||
&UnorderedOrGreaterThan => "ugt",
|
&UnorderedOrGreaterThan => "ugt",
|
||||||
&UnorderedOrGreaterThanOrEqual => "uge",
|
&UnorderedOrGreaterThanOrEqual => "uge",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -180,19 +180,20 @@ impl DataFlowGraph {
|
|||||||
|
|
||||||
for _ in 0..self.insts.len() {
|
for _ in 0..self.insts.len() {
|
||||||
v = self.resolve_aliases(match v.expand() {
|
v = self.resolve_aliases(match v.expand() {
|
||||||
Direct(inst) => {
|
Direct(inst) => {
|
||||||
match self[inst] {
|
match self[inst] {
|
||||||
InstructionData::Unary { opcode, arg, .. } => {
|
InstructionData::Unary { opcode, arg, .. } => {
|
||||||
match opcode {
|
match opcode {
|
||||||
Opcode::Copy | Opcode::Spill | Opcode::Fill => arg,
|
Opcode::Copy | Opcode::Spill |
|
||||||
_ => return v,
|
Opcode::Fill => arg,
|
||||||
}
|
_ => return v,
|
||||||
}
|
}
|
||||||
_ => return v,
|
}
|
||||||
}
|
_ => return v,
|
||||||
}
|
}
|
||||||
_ => return v,
|
}
|
||||||
});
|
_ => return v,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
panic!("Copy loop detected for {}", value);
|
panic!("Copy loop detected for {}", value);
|
||||||
}
|
}
|
||||||
@@ -361,11 +362,11 @@ impl DataFlowGraph {
|
|||||||
for res_idx in (0..var_results).rev() {
|
for res_idx in (0..var_results).rev() {
|
||||||
if let Some(ty) = first_type {
|
if let Some(ty) = first_type {
|
||||||
head = Some(self.make_value(ValueData::Inst {
|
head = Some(self.make_value(ValueData::Inst {
|
||||||
ty: ty,
|
ty: ty,
|
||||||
num: (total_results - rev_num) as u16,
|
num: (total_results - rev_num) as u16,
|
||||||
inst: inst,
|
inst: inst,
|
||||||
next: head.into(),
|
next: head.into(),
|
||||||
}));
|
}));
|
||||||
rev_num += 1;
|
rev_num += 1;
|
||||||
}
|
}
|
||||||
first_type = Some(self.signatures[sig].return_types[res_idx].value_type);
|
first_type = Some(self.signatures[sig].return_types[res_idx].value_type);
|
||||||
@@ -376,11 +377,11 @@ impl DataFlowGraph {
|
|||||||
for res_idx in (0..fixed_results).rev() {
|
for res_idx in (0..fixed_results).rev() {
|
||||||
if let Some(ty) = first_type {
|
if let Some(ty) = first_type {
|
||||||
head = Some(self.make_value(ValueData::Inst {
|
head = Some(self.make_value(ValueData::Inst {
|
||||||
ty: ty,
|
ty: ty,
|
||||||
num: (total_results - rev_num) as u16,
|
num: (total_results - rev_num) as u16,
|
||||||
inst: inst,
|
inst: inst,
|
||||||
next: head.into(),
|
next: head.into(),
|
||||||
}));
|
}));
|
||||||
rev_num += 1;
|
rev_num += 1;
|
||||||
}
|
}
|
||||||
first_type = Some(constraints.result_type(res_idx, ctrl_typevar));
|
first_type = Some(constraints.result_type(res_idx, ctrl_typevar));
|
||||||
@@ -474,11 +475,11 @@ impl DataFlowGraph {
|
|||||||
|
|
||||||
// Not a fixed result, try to extract a return type from the call signature.
|
// Not a fixed result, try to extract a return type from the call signature.
|
||||||
self.call_signature(inst).and_then(|sigref| {
|
self.call_signature(inst).and_then(|sigref| {
|
||||||
self.signatures[sigref]
|
self.signatures[sigref]
|
||||||
.return_types
|
.return_types
|
||||||
.get(result_idx - fixed_results)
|
.get(result_idx - fixed_results)
|
||||||
.map(|&arg| arg.value_type)
|
.map(|&arg| arg.value_type)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,11 +524,11 @@ impl DataFlowGraph {
|
|||||||
/// Append an argument with type `ty` to `ebb`.
|
/// Append an argument with type `ty` to `ebb`.
|
||||||
pub fn append_ebb_arg(&mut self, ebb: Ebb, ty: Type) -> Value {
|
pub fn append_ebb_arg(&mut self, ebb: Ebb, ty: Type) -> Value {
|
||||||
let val = self.make_value(ValueData::Arg {
|
let val = self.make_value(ValueData::Arg {
|
||||||
ty: ty,
|
ty: ty,
|
||||||
ebb: ebb,
|
ebb: ebb,
|
||||||
num: 0,
|
num: 0,
|
||||||
next: None.into(),
|
next: None.into(),
|
||||||
});
|
});
|
||||||
self.put_ebb_arg(ebb, val);
|
self.put_ebb_arg(ebb, val);
|
||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,9 +50,11 @@ impl Signature {
|
|||||||
let bytes = self.argument_types
|
let bytes = self.argument_types
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|arg| match arg.location {
|
.filter_map(|arg| match arg.location {
|
||||||
ArgumentLoc::Stack(offset) => Some(offset + arg.value_type.bits() as u32 / 8),
|
ArgumentLoc::Stack(offset) => {
|
||||||
_ => None,
|
Some(offset + arg.value_type.bits() as u32 / 8)
|
||||||
})
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
.fold(0, cmp::max);
|
.fold(0, cmp::max);
|
||||||
self.argument_bytes = Some(bytes);
|
self.argument_bytes = Some(bytes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,20 +252,20 @@ fn parse_float(s: &str, w: u8, t: u8) -> Result<u64, &'static str> {
|
|||||||
if s2.starts_with("NaN:0x") {
|
if s2.starts_with("NaN:0x") {
|
||||||
// Quiet NaN with payload.
|
// Quiet NaN with payload.
|
||||||
return match u64::from_str_radix(&s2[6..], 16) {
|
return match u64::from_str_radix(&s2[6..], 16) {
|
||||||
Ok(payload) if payload < quiet_bit => {
|
Ok(payload) if payload < quiet_bit => {
|
||||||
Ok(sign_bit | max_e_bits | quiet_bit | payload)
|
Ok(sign_bit | max_e_bits | quiet_bit | payload)
|
||||||
}
|
}
|
||||||
_ => Err("Invalid NaN payload"),
|
_ => Err("Invalid NaN payload"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if s2.starts_with("sNaN:0x") {
|
if s2.starts_with("sNaN:0x") {
|
||||||
// Signaling NaN with payload.
|
// Signaling NaN with payload.
|
||||||
return match u64::from_str_radix(&s2[7..], 16) {
|
return match u64::from_str_radix(&s2[7..], 16) {
|
||||||
Ok(payload) if 0 < payload && payload < quiet_bit => {
|
Ok(payload) if 0 < payload && payload < quiet_bit => {
|
||||||
Ok(sign_bit | max_e_bits | payload)
|
Ok(sign_bit | max_e_bits | payload)
|
||||||
}
|
}
|
||||||
_ => Err("Invalid sNaN payload"),
|
_ => Err("Invalid sNaN payload"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err("Float must be hexadecimal");
|
return Err("Float must be hexadecimal");
|
||||||
|
|||||||
@@ -66,7 +66,10 @@ impl JumpTableData {
|
|||||||
///
|
///
|
||||||
/// This returns an iterator that skips any empty slots in the table.
|
/// This returns an iterator that skips any empty slots in the table.
|
||||||
pub fn entries<'a>(&'a self) -> Entries {
|
pub fn entries<'a>(&'a self) -> Entries {
|
||||||
Entries(self.table.iter().cloned().enumerate())
|
Entries(self.table
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.enumerate())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the whole table as a mutable slice.
|
/// Access the whole table as a mutable slice.
|
||||||
@@ -101,7 +104,10 @@ impl Display for JumpTableData {
|
|||||||
Some(first) => write!(fmt, "jump_table {}", first)?,
|
Some(first) => write!(fmt, "jump_table {}", first)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
for dest in self.table.iter().skip(1).map(|e| e.expand()) {
|
for dest in self.table
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.map(|e| e.expand()) {
|
||||||
match dest {
|
match dest {
|
||||||
None => write!(fmt, ", 0")?,
|
None => write!(fmt, ", 0")?,
|
||||||
Some(ebb) => write!(fmt, ", {}", ebb)?,
|
Some(ebb) => write!(fmt, ", {}", ebb)?,
|
||||||
|
|||||||
@@ -125,10 +125,7 @@ impl Layout {
|
|||||||
/// Get the last sequence number in `ebb`.
|
/// Get the last sequence number in `ebb`.
|
||||||
fn last_ebb_seq(&self, ebb: Ebb) -> SequenceNumber {
|
fn last_ebb_seq(&self, ebb: Ebb) -> SequenceNumber {
|
||||||
// Get the seq of the last instruction if it exists, otherwise use the EBB header seq.
|
// Get the seq of the last instruction if it exists, otherwise use the EBB header seq.
|
||||||
self.ebbs[ebb]
|
self.ebbs[ebb].last_inst.map(|inst| self.insts[inst].seq).unwrap_or(self.ebbs[ebb].seq)
|
||||||
.last_inst
|
|
||||||
.map(|inst| self.insts[inst].seq)
|
|
||||||
.unwrap_or(self.ebbs[ebb].seq)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assign a valid sequence number to `ebb` such that the numbers are still monotonic. This may
|
/// Assign a valid sequence number to `ebb` such that the numbers are still monotonic. This may
|
||||||
@@ -439,8 +436,8 @@ impl Layout {
|
|||||||
/// Insert `inst` before the instruction `before` in the same EBB.
|
/// Insert `inst` before the instruction `before` in the same EBB.
|
||||||
pub fn insert_inst(&mut self, inst: Inst, before: Inst) {
|
pub fn insert_inst(&mut self, inst: Inst, before: Inst) {
|
||||||
assert_eq!(self.inst_ebb(inst), None);
|
assert_eq!(self.inst_ebb(inst), None);
|
||||||
let ebb = self.inst_ebb(before)
|
let ebb =
|
||||||
.expect("Instruction before insertion point not in the layout");
|
self.inst_ebb(before).expect("Instruction before insertion point not in the layout");
|
||||||
let after = self.insts[before].prev;
|
let after = self.insts[before].prev;
|
||||||
{
|
{
|
||||||
let inst_node = self.insts.ensure(inst);
|
let inst_node = self.insts.ensure(inst);
|
||||||
@@ -488,8 +485,8 @@ impl Layout {
|
|||||||
/// i4
|
/// i4
|
||||||
/// ```
|
/// ```
|
||||||
pub fn split_ebb(&mut self, new_ebb: Ebb, before: Inst) {
|
pub fn split_ebb(&mut self, new_ebb: Ebb, before: Inst) {
|
||||||
let old_ebb = self.inst_ebb(before)
|
let old_ebb =
|
||||||
.expect("The `before` instruction must be in the layout");
|
self.inst_ebb(before).expect("The `before` instruction must be in the layout");
|
||||||
assert!(!self.is_ebb_inserted(new_ebb));
|
assert!(!self.is_ebb_inserted(new_ebb));
|
||||||
|
|
||||||
// Insert new_ebb after old_ebb.
|
// Insert new_ebb after old_ebb.
|
||||||
|
|||||||
@@ -348,7 +348,12 @@ mod tests {
|
|||||||
assert_eq!(big.bits(), 64 * 256);
|
assert_eq!(big.bits(), 64 * 256);
|
||||||
|
|
||||||
assert_eq!(big.half_vector().unwrap().to_string(), "f64x128");
|
assert_eq!(big.half_vector().unwrap().to_string(), "f64x128");
|
||||||
assert_eq!(B1.by(2).unwrap().half_vector().unwrap().to_string(), "b1");
|
assert_eq!(B1.by(2)
|
||||||
|
.unwrap()
|
||||||
|
.half_vector()
|
||||||
|
.unwrap()
|
||||||
|
.to_string(),
|
||||||
|
"b1");
|
||||||
assert_eq!(I32.half_vector(), None);
|
assert_eq!(I32.half_vector(), None);
|
||||||
assert_eq!(VOID.half_vector(), None);
|
assert_eq!(VOID.half_vector(), None);
|
||||||
|
|
||||||
@@ -378,7 +383,12 @@ mod tests {
|
|||||||
assert_eq!(B1.by(8).unwrap().to_string(), "b1x8");
|
assert_eq!(B1.by(8).unwrap().to_string(), "b1x8");
|
||||||
assert_eq!(B8.by(1).unwrap().to_string(), "b8");
|
assert_eq!(B8.by(1).unwrap().to_string(), "b8");
|
||||||
assert_eq!(B16.by(256).unwrap().to_string(), "b16x256");
|
assert_eq!(B16.by(256).unwrap().to_string(), "b16x256");
|
||||||
assert_eq!(B32.by(4).unwrap().by(2).unwrap().to_string(), "b32x8");
|
assert_eq!(B32.by(4)
|
||||||
|
.unwrap()
|
||||||
|
.by(2)
|
||||||
|
.unwrap()
|
||||||
|
.to_string(),
|
||||||
|
"b32x8");
|
||||||
assert_eq!(B64.by(8).unwrap().to_string(), "b64x8");
|
assert_eq!(B64.by(8).unwrap().to_string(), "b64x8");
|
||||||
assert_eq!(I8.by(64).unwrap().to_string(), "i8x64");
|
assert_eq!(I8.by(64).unwrap().to_string(), "i8x64");
|
||||||
assert_eq!(F64.by(2).unwrap().to_string(), "f64x2");
|
assert_eq!(F64.by(2).unwrap().to_string(), "f64x2");
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ fn isa_constructor(shared_flags: shared_settings::Flags,
|
|||||||
&enc_tables::LEVEL1_A32[..]
|
&enc_tables::LEVEL1_A32[..]
|
||||||
};
|
};
|
||||||
Box::new(Isa {
|
Box::new(Isa {
|
||||||
isa_flags: settings::Flags::new(&shared_flags, builder),
|
isa_flags: settings::Flags::new(&shared_flags, builder),
|
||||||
shared_flags: shared_flags,
|
shared_flags: shared_flags,
|
||||||
cpumode: level1,
|
cpumode: level1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TargetIsa for Isa {
|
impl TargetIsa for Isa {
|
||||||
@@ -58,13 +58,13 @@ impl TargetIsa for Isa {
|
|||||||
inst.opcode(),
|
inst.opcode(),
|
||||||
self.cpumode,
|
self.cpumode,
|
||||||
&enc_tables::LEVEL2[..])
|
&enc_tables::LEVEL2[..])
|
||||||
.and_then(|enclist_offset| {
|
.and_then(|enclist_offset| {
|
||||||
general_encoding(enclist_offset,
|
general_encoding(enclist_offset,
|
||||||
&enc_tables::ENCLISTS[..],
|
&enc_tables::ENCLISTS[..],
|
||||||
|instp| enc_tables::check_instp(inst, instp),
|
|instp| enc_tables::check_instp(inst, instp),
|
||||||
|isap| self.isa_flags.numbered_predicate(isap as usize))
|
|isap| self.isa_flags.numbered_predicate(isap as usize))
|
||||||
.ok_or(Legalize::Expand)
|
.ok_or(Legalize::Expand)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recipe_names(&self) -> &'static [&'static str] {
|
fn recipe_names(&self) -> &'static [&'static str] {
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ fn isa_constructor(shared_flags: shared_settings::Flags,
|
|||||||
builder: &shared_settings::Builder)
|
builder: &shared_settings::Builder)
|
||||||
-> Box<TargetIsa> {
|
-> Box<TargetIsa> {
|
||||||
Box::new(Isa {
|
Box::new(Isa {
|
||||||
isa_flags: settings::Flags::new(&shared_flags, builder),
|
isa_flags: settings::Flags::new(&shared_flags, builder),
|
||||||
shared_flags: shared_flags,
|
shared_flags: shared_flags,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TargetIsa for Isa {
|
impl TargetIsa for Isa {
|
||||||
@@ -51,13 +51,13 @@ impl TargetIsa for Isa {
|
|||||||
inst.opcode(),
|
inst.opcode(),
|
||||||
&enc_tables::LEVEL1_A64[..],
|
&enc_tables::LEVEL1_A64[..],
|
||||||
&enc_tables::LEVEL2[..])
|
&enc_tables::LEVEL2[..])
|
||||||
.and_then(|enclist_offset| {
|
.and_then(|enclist_offset| {
|
||||||
general_encoding(enclist_offset,
|
general_encoding(enclist_offset,
|
||||||
&enc_tables::ENCLISTS[..],
|
&enc_tables::ENCLISTS[..],
|
||||||
|instp| enc_tables::check_instp(inst, instp),
|
|instp| enc_tables::check_instp(inst, instp),
|
||||||
|isap| self.isa_flags.numbered_predicate(isap as usize))
|
|isap| self.isa_flags.numbered_predicate(isap as usize))
|
||||||
.ok_or(Legalize::Expand)
|
.ok_or(Legalize::Expand)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recipe_names(&self) -> &'static [&'static str] {
|
fn recipe_names(&self) -> &'static [&'static str] {
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ fn isa_constructor(shared_flags: shared_settings::Flags,
|
|||||||
&enc_tables::LEVEL1_I32[..]
|
&enc_tables::LEVEL1_I32[..]
|
||||||
};
|
};
|
||||||
Box::new(Isa {
|
Box::new(Isa {
|
||||||
isa_flags: settings::Flags::new(&shared_flags, builder),
|
isa_flags: settings::Flags::new(&shared_flags, builder),
|
||||||
shared_flags: shared_flags,
|
shared_flags: shared_flags,
|
||||||
cpumode: level1,
|
cpumode: level1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TargetIsa for Isa {
|
impl TargetIsa for Isa {
|
||||||
@@ -58,13 +58,13 @@ impl TargetIsa for Isa {
|
|||||||
inst.opcode(),
|
inst.opcode(),
|
||||||
self.cpumode,
|
self.cpumode,
|
||||||
&enc_tables::LEVEL2[..])
|
&enc_tables::LEVEL2[..])
|
||||||
.and_then(|enclist_offset| {
|
.and_then(|enclist_offset| {
|
||||||
general_encoding(enclist_offset,
|
general_encoding(enclist_offset,
|
||||||
&enc_tables::ENCLISTS[..],
|
&enc_tables::ENCLISTS[..],
|
||||||
|instp| enc_tables::check_instp(inst, instp),
|
|instp| enc_tables::check_instp(inst, instp),
|
||||||
|isap| self.isa_flags.numbered_predicate(isap as usize))
|
|isap| self.isa_flags.numbered_predicate(isap as usize))
|
||||||
.ok_or(Legalize::Expand)
|
.ok_or(Legalize::Expand)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recipe_names(&self) -> &'static [&'static str] {
|
fn recipe_names(&self) -> &'static [&'static str] {
|
||||||
|
|||||||
@@ -67,10 +67,10 @@ impl RegBank {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.and_then(|offset| if offset < self.units {
|
.and_then(|offset| if offset < self.units {
|
||||||
Some(offset + self.first_unit)
|
Some(offset + self.first_unit)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write `regunit` to `w`, assuming that it belongs to this bank.
|
/// Write `regunit` to `w`, assuming that it belongs to this bank.
|
||||||
@@ -199,7 +199,10 @@ impl RegInfo {
|
|||||||
|
|
||||||
/// Try to parse a regunit name. The name is not expected to begin with `%`.
|
/// Try to parse a regunit name. The name is not expected to begin with `%`.
|
||||||
pub fn parse_regunit(&self, name: &str) -> Option<RegUnit> {
|
pub fn parse_regunit(&self, name: &str) -> Option<RegUnit> {
|
||||||
self.banks.iter().filter_map(|b| b.parse_regunit(name)).next()
|
self.banks
|
||||||
|
.iter()
|
||||||
|
.filter_map(|b| b.parse_regunit(name))
|
||||||
|
.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make a temporary object that can display a register unit.
|
/// Make a temporary object that can display a register unit.
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ fn isa_constructor(shared_flags: shared_settings::Flags,
|
|||||||
&enc_tables::LEVEL1_RV32[..]
|
&enc_tables::LEVEL1_RV32[..]
|
||||||
};
|
};
|
||||||
Box::new(Isa {
|
Box::new(Isa {
|
||||||
isa_flags: settings::Flags::new(&shared_flags, builder),
|
isa_flags: settings::Flags::new(&shared_flags, builder),
|
||||||
shared_flags: shared_flags,
|
shared_flags: shared_flags,
|
||||||
cpumode: level1,
|
cpumode: level1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TargetIsa for Isa {
|
impl TargetIsa for Isa {
|
||||||
@@ -59,13 +59,13 @@ impl TargetIsa for Isa {
|
|||||||
inst.opcode(),
|
inst.opcode(),
|
||||||
self.cpumode,
|
self.cpumode,
|
||||||
&enc_tables::LEVEL2[..])
|
&enc_tables::LEVEL2[..])
|
||||||
.and_then(|enclist_offset| {
|
.and_then(|enclist_offset| {
|
||||||
general_encoding(enclist_offset,
|
general_encoding(enclist_offset,
|
||||||
&enc_tables::ENCLISTS[..],
|
&enc_tables::ENCLISTS[..],
|
||||||
|instp| enc_tables::check_instp(inst, instp),
|
|instp| enc_tables::check_instp(inst, instp),
|
||||||
|isap| self.isa_flags.numbered_predicate(isap as usize))
|
|isap| self.isa_flags.numbered_predicate(isap as usize))
|
||||||
.ok_or(Legalize::Expand)
|
.ok_or(Legalize::Expand)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recipe_names(&self) -> &'static [&'static str] {
|
fn recipe_names(&self) -> &'static [&'static str] {
|
||||||
|
|||||||
@@ -35,7 +35,10 @@ mod tests {
|
|||||||
|
|
||||||
fn check(x: &[u32], want: &[u32]) {
|
fn check(x: &[u32], want: &[u32]) {
|
||||||
assert_eq!(x.len(), want.len());
|
assert_eq!(x.len(), want.len());
|
||||||
let want_count = want.iter().cloned().filter(|&x| x % 10 == 0).count();
|
let want_count = want.iter()
|
||||||
|
.cloned()
|
||||||
|
.filter(|&x| x % 10 == 0)
|
||||||
|
.count();
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
v.extend(x.iter().cloned());
|
v.extend(x.iter().cloned());
|
||||||
let count = partition_slice(&mut v[..], |&x| x % 10 == 0);
|
let count = partition_slice(&mut v[..], |&x| x % 10 == 0);
|
||||||
|
|||||||
@@ -118,21 +118,21 @@ mod tests {
|
|||||||
|
|
||||||
// Register classes for testing.
|
// Register classes for testing.
|
||||||
const GPR: RegClass = &RegClassData {
|
const GPR: RegClass = &RegClassData {
|
||||||
name: "GPR",
|
name: "GPR",
|
||||||
index: 0,
|
index: 0,
|
||||||
width: 1,
|
width: 1,
|
||||||
first: 28,
|
first: 28,
|
||||||
subclasses: 0,
|
subclasses: 0,
|
||||||
mask: [0xf0000000, 0x0000000f, 0],
|
mask: [0xf0000000, 0x0000000f, 0],
|
||||||
};
|
};
|
||||||
const DPR: RegClass = &RegClassData {
|
const DPR: RegClass = &RegClassData {
|
||||||
name: "DPR",
|
name: "DPR",
|
||||||
index: 0,
|
index: 0,
|
||||||
width: 2,
|
width: 2,
|
||||||
first: 28,
|
first: 28,
|
||||||
subclasses: 0,
|
subclasses: 0,
|
||||||
mask: [0x50000000, 0x0000000a, 0],
|
mask: [0x50000000, 0x0000000a, 0],
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn put_and_take() {
|
fn put_and_take() {
|
||||||
|
|||||||
@@ -200,7 +200,10 @@ impl<'a> Context<'a> {
|
|||||||
|
|
||||||
for lv in liveins {
|
for lv in liveins {
|
||||||
let value = lv.value;
|
let value = lv.value;
|
||||||
let affinity = self.liveness.get(value).expect("No live range for live-in").affinity;
|
let affinity = self.liveness
|
||||||
|
.get(value)
|
||||||
|
.expect("No live range for live-in")
|
||||||
|
.affinity;
|
||||||
if let Affinity::Reg(rc_index) = affinity {
|
if let Affinity::Reg(rc_index) = affinity {
|
||||||
let regclass = self.reginfo.rc(rc_index);
|
let regclass = self.reginfo.rc(rc_index);
|
||||||
match func.locations[value] {
|
match func.locations[value] {
|
||||||
|
|||||||
@@ -69,10 +69,10 @@ impl LiveValueVec {
|
|||||||
/// Add a new live value to `values`.
|
/// Add a new live value to `values`.
|
||||||
fn push(&mut self, value: Value, endpoint: Inst, affinity: Affinity) {
|
fn push(&mut self, value: Value, endpoint: Inst, affinity: Affinity) {
|
||||||
self.values.push(LiveValue {
|
self.values.push(LiveValue {
|
||||||
value: value,
|
value: value,
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
affinity: affinity,
|
affinity: affinity,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove all elements.
|
/// Remove all elements.
|
||||||
@@ -167,8 +167,7 @@ impl LiveValueTracker {
|
|||||||
self.idom_sets.get(&idom).expect("No stored live set for dominator");
|
self.idom_sets.get(&idom).expect("No stored live set for dominator");
|
||||||
// Get just the values that are live-in to `ebb`.
|
// Get just the values that are live-in to `ebb`.
|
||||||
for &value in idom_live_list.as_slice(&self.idom_pool) {
|
for &value in idom_live_list.as_slice(&self.idom_pool) {
|
||||||
let lr = liveness.get(value)
|
let lr = liveness.get(value).expect("Immediate dominator value has no live range");
|
||||||
.expect("Immediate dominator value has no live range");
|
|
||||||
|
|
||||||
// Check if this value is live-in here.
|
// Check if this value is live-in here.
|
||||||
if let Some(endpoint) = lr.livein_local_end(ebb, program_order) {
|
if let Some(endpoint) = lr.livein_local_end(ebb, program_order) {
|
||||||
@@ -260,13 +259,16 @@ impl LiveValueTracker {
|
|||||||
|
|
||||||
/// Save the current set of live values so it is associated with `idom`.
|
/// Save the current set of live values so it is associated with `idom`.
|
||||||
fn save_idom_live_set(&mut self, idom: Inst) {
|
fn save_idom_live_set(&mut self, idom: Inst) {
|
||||||
let values = self.live.values.iter().map(|lv| lv.value);
|
let values = self.live
|
||||||
|
.values
|
||||||
|
.iter()
|
||||||
|
.map(|lv| lv.value);
|
||||||
let pool = &mut self.idom_pool;
|
let pool = &mut self.idom_pool;
|
||||||
// If there already is a set saved for `idom`, just keep it.
|
// If there already is a set saved for `idom`, just keep it.
|
||||||
self.idom_sets.entry(idom).or_insert_with(|| {
|
self.idom_sets.entry(idom).or_insert_with(|| {
|
||||||
let mut list = ValueList::default();
|
let mut list = ValueList::default();
|
||||||
list.extend(values, pool);
|
list.extend(values, pool);
|
||||||
list
|
list
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -315,8 +315,10 @@ impl Liveness {
|
|||||||
let recipe = func.encodings[inst].recipe();
|
let recipe = func.encodings[inst].recipe();
|
||||||
// Iterator of constraints, one per value operand.
|
// Iterator of constraints, one per value operand.
|
||||||
// TODO: Should we fail here if the instruction doesn't have a valid encoding?
|
// TODO: Should we fail here if the instruction doesn't have a valid encoding?
|
||||||
let mut operand_constraints =
|
let mut operand_constraints = recipe_constraints.get(recipe)
|
||||||
recipe_constraints.get(recipe).map(|c| c.ins).unwrap_or(&[]).iter();
|
.map(|c| c.ins)
|
||||||
|
.unwrap_or(&[])
|
||||||
|
.iter();
|
||||||
|
|
||||||
for &arg in func.dfg[inst].arguments(&func.dfg.value_lists) {
|
for &arg in func.dfg[inst].arguments(&func.dfg.value_lists) {
|
||||||
// Get the live range, create it as a dead range if necessary.
|
// Get the live range, create it as a dead range if necessary.
|
||||||
|
|||||||
@@ -221,16 +221,14 @@ impl LiveRange {
|
|||||||
/// Return `Ok(n)` if `liveins[n]` already contains `ebb`.
|
/// Return `Ok(n)` if `liveins[n]` already contains `ebb`.
|
||||||
/// Otherwise, return `Err(n)` with the index where such an interval should be inserted.
|
/// Otherwise, return `Err(n)` with the index where such an interval should be inserted.
|
||||||
fn find_ebb_interval<PO: ProgramOrder>(&self, ebb: Ebb, order: &PO) -> Result<usize, usize> {
|
fn find_ebb_interval<PO: ProgramOrder>(&self, ebb: Ebb, order: &PO) -> Result<usize, usize> {
|
||||||
self.liveins
|
self.liveins.binary_search_by(|intv| order.cmp(intv.begin, ebb)).or_else(|n| {
|
||||||
.binary_search_by(|intv| order.cmp(intv.begin, ebb))
|
// The interval at `n-1` may cover `ebb`.
|
||||||
.or_else(|n| {
|
if n > 0 && order.cmp(self.liveins[n - 1].end, ebb) == Ordering::Greater {
|
||||||
// The interval at `n-1` may cover `ebb`.
|
Ok(n - 1)
|
||||||
if n > 0 && order.cmp(self.liveins[n - 1].end, ebb) == Ordering::Greater {
|
} else {
|
||||||
Ok(n - 1)
|
Err(n)
|
||||||
} else {
|
}
|
||||||
Err(n)
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extend the local interval for `ebb` so it reaches `to` which must belong to `ebb`.
|
/// Extend the local interval for `ebb` so it reaches `to` which must belong to `ebb`.
|
||||||
|
|||||||
@@ -157,9 +157,8 @@ impl<'a> Verifier<'a> {
|
|||||||
|
|
||||||
let fixed_results = inst_data.opcode().constraints().fixed_results();
|
let fixed_results = inst_data.opcode().constraints().fixed_results();
|
||||||
// var_results is 0 if we aren't a call instruction
|
// var_results is 0 if we aren't a call instruction
|
||||||
let var_results = dfg.call_signature(inst)
|
let var_results =
|
||||||
.map(|sig| dfg.signatures[sig].return_types.len())
|
dfg.call_signature(inst).map(|sig| dfg.signatures[sig].return_types.len()).unwrap_or(0);
|
||||||
.unwrap_or(0);
|
|
||||||
let total_results = fixed_results + var_results;
|
let total_results = fixed_results + var_results;
|
||||||
|
|
||||||
if total_results == 0 {
|
if total_results == 0 {
|
||||||
@@ -247,7 +246,10 @@ impl<'a> Verifier<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn verify_sig_ref(&self, inst: Inst, s: SigRef) -> Result<()> {
|
fn verify_sig_ref(&self, inst: Inst, s: SigRef) -> Result<()> {
|
||||||
if !self.func.dfg.signatures.is_valid(s) {
|
if !self.func
|
||||||
|
.dfg
|
||||||
|
.signatures
|
||||||
|
.is_valid(s) {
|
||||||
err!(inst, "invalid signature reference {}", s)
|
err!(inst, "invalid signature reference {}", s)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -255,7 +257,10 @@ impl<'a> Verifier<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn verify_func_ref(&self, inst: Inst, f: FuncRef) -> Result<()> {
|
fn verify_func_ref(&self, inst: Inst, f: FuncRef) -> Result<()> {
|
||||||
if !self.func.dfg.ext_funcs.is_valid(f) {
|
if !self.func
|
||||||
|
.dfg
|
||||||
|
.ext_funcs
|
||||||
|
.is_valid(f) {
|
||||||
err!(inst, "invalid function reference {}", f)
|
err!(inst, "invalid function reference {}", f)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -330,9 +335,9 @@ mod tests {
|
|||||||
let ebb0 = func.dfg.make_ebb();
|
let ebb0 = func.dfg.make_ebb();
|
||||||
func.layout.append_ebb(ebb0);
|
func.layout.append_ebb(ebb0);
|
||||||
let nullary_with_bad_opcode = func.dfg.make_inst(InstructionData::Nullary {
|
let nullary_with_bad_opcode = func.dfg.make_inst(InstructionData::Nullary {
|
||||||
opcode: Opcode::Jump,
|
opcode: Opcode::Jump,
|
||||||
ty: types::VOID,
|
ty: types::VOID,
|
||||||
});
|
});
|
||||||
func.layout.append_inst(nullary_with_bad_opcode, ebb0);
|
func.layout.append_inst(nullary_with_bad_opcode, ebb0);
|
||||||
let verifier = Verifier::new(&func);
|
let verifier = Verifier::new(&func);
|
||||||
assert_err_with_msg!(verifier.run(), "instruction format");
|
assert_err_with_msg!(verifier.run(), "instruction format");
|
||||||
|
|||||||
@@ -188,7 +188,11 @@ fn write_instruction(w: &mut Write,
|
|||||||
for r in func.dfg.inst_results(inst) {
|
for r in func.dfg.inst_results(inst) {
|
||||||
write!(s,
|
write!(s,
|
||||||
",{}",
|
",{}",
|
||||||
func.locations.get(r).cloned().unwrap_or_default().display(®s))?
|
func.locations
|
||||||
|
.get(r)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.display(®s))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write!(s, "]")?;
|
write!(s, "]")?;
|
||||||
|
|||||||
@@ -270,7 +270,10 @@ impl<'a> State<'a> {
|
|||||||
// Get the offset following the match that defined `var`, or 0 if var is an environment
|
// Get the offset following the match that defined `var`, or 0 if var is an environment
|
||||||
// variable or unknown.
|
// variable or unknown.
|
||||||
fn def_offset(&self, var: &str) -> usize {
|
fn def_offset(&self, var: &str) -> usize {
|
||||||
self.vars.get(var).map(|&VarDef { offset, .. }| offset).unwrap_or(0)
|
self.vars
|
||||||
|
.get(var)
|
||||||
|
.map(|&VarDef { offset, .. }| offset)
|
||||||
|
.unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the offset of the beginning of the next line after `pos`.
|
// Get the offset of the beginning of the next line after `pos`.
|
||||||
@@ -344,13 +347,13 @@ impl<'a> State<'a> {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
Ok(if let Some((b, e)) = matched_range {
|
Ok(if let Some((b, e)) = matched_range {
|
||||||
let r = (range.0 + b, range.0 + e);
|
let r = (range.0 + b, range.0 + e);
|
||||||
self.recorder.matched_check(rx.as_str(), r);
|
self.recorder.matched_check(rx.as_str(), r);
|
||||||
Some(r)
|
Some(r)
|
||||||
} else {
|
} else {
|
||||||
self.recorder.missed_check(rx.as_str(), range);
|
self.recorder.missed_check(rx.as_str(), range);
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,49 +148,49 @@ impl<'a> Recorder for Explainer<'a> {
|
|||||||
|
|
||||||
fn matched_check(&mut self, regex: &str, matched: MatchRange) {
|
fn matched_check(&mut self, regex: &str, matched: MatchRange) {
|
||||||
self.matches.push(Match {
|
self.matches.push(Match {
|
||||||
directive: self.directive,
|
directive: self.directive,
|
||||||
is_match: true,
|
is_match: true,
|
||||||
is_not: false,
|
is_not: false,
|
||||||
regex: regex.to_owned(),
|
regex: regex.to_owned(),
|
||||||
range: matched,
|
range: matched,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matched_not(&mut self, regex: &str, matched: MatchRange) {
|
fn matched_not(&mut self, regex: &str, matched: MatchRange) {
|
||||||
self.matches.push(Match {
|
self.matches.push(Match {
|
||||||
directive: self.directive,
|
directive: self.directive,
|
||||||
is_match: true,
|
is_match: true,
|
||||||
is_not: true,
|
is_not: true,
|
||||||
regex: regex.to_owned(),
|
regex: regex.to_owned(),
|
||||||
range: matched,
|
range: matched,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn missed_check(&mut self, regex: &str, searched: MatchRange) {
|
fn missed_check(&mut self, regex: &str, searched: MatchRange) {
|
||||||
self.matches.push(Match {
|
self.matches.push(Match {
|
||||||
directive: self.directive,
|
directive: self.directive,
|
||||||
is_match: false,
|
is_match: false,
|
||||||
is_not: false,
|
is_not: false,
|
||||||
regex: regex.to_owned(),
|
regex: regex.to_owned(),
|
||||||
range: searched,
|
range: searched,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn missed_not(&mut self, regex: &str, searched: MatchRange) {
|
fn missed_not(&mut self, regex: &str, searched: MatchRange) {
|
||||||
self.matches.push(Match {
|
self.matches.push(Match {
|
||||||
directive: self.directive,
|
directive: self.directive,
|
||||||
is_match: false,
|
is_match: false,
|
||||||
is_not: true,
|
is_not: true,
|
||||||
regex: regex.to_owned(),
|
regex: regex.to_owned(),
|
||||||
range: searched,
|
range: searched,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn defined_var(&mut self, varname: &str, value: &str) {
|
fn defined_var(&mut self, varname: &str, value: &str) {
|
||||||
self.vardefs.push(VarDef {
|
self.vardefs.push(VarDef {
|
||||||
directive: self.directive,
|
directive: self.directive,
|
||||||
varname: varname.to_owned(),
|
varname: varname.to_owned(),
|
||||||
value: value.to_owned(),
|
value: value.to_owned(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ impl Pattern {
|
|||||||
// All remaining possibilities start with `$(`.
|
// All remaining possibilities start with `$(`.
|
||||||
if s.len() < 2 || !s.starts_with("$(") {
|
if s.len() < 2 || !s.starts_with("$(") {
|
||||||
return Err(Error::Syntax("pattern syntax error, use $$ to match a single $"
|
return Err(Error::Syntax("pattern syntax error, use $$ to match a single $"
|
||||||
.to_string()));
|
.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match the variable name, allowing for an empty varname in `$()`, or `$(=...)`.
|
// Match the variable name, allowing for an empty varname in `$()`, or `$(=...)`.
|
||||||
@@ -164,14 +164,14 @@ impl Pattern {
|
|||||||
}
|
}
|
||||||
let refname = s[refname_begin..refname_end].to_string();
|
let refname = s[refname_begin..refname_end].to_string();
|
||||||
return if let Some(defidx) = def {
|
return if let Some(defidx) = def {
|
||||||
Ok((Part::DefVar {
|
Ok((Part::DefVar {
|
||||||
def: defidx,
|
def: defidx,
|
||||||
var: refname,
|
var: refname,
|
||||||
},
|
},
|
||||||
refname_end + 1))
|
refname_end + 1))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Syntax(format!("expected variable name in $(=${})", refname)))
|
Err(Error::Syntax(format!("expected variable name in $(=${})", refname)))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Last case: `$(var=...)` where `...` is a regular expression, possibly containing matched
|
// Last case: `$(var=...)` where `...` is a regular expression, possibly containing matched
|
||||||
|
|||||||
@@ -55,9 +55,9 @@ pub struct LocatedToken<'a> {
|
|||||||
/// Wrap up a `Token` with the given location.
|
/// Wrap up a `Token` with the given location.
|
||||||
fn token<'a>(token: Token<'a>, loc: Location) -> Result<LocatedToken<'a>, LocatedError> {
|
fn token<'a>(token: Token<'a>, loc: Location) -> Result<LocatedToken<'a>, LocatedError> {
|
||||||
Ok(LocatedToken {
|
Ok(LocatedToken {
|
||||||
token: token,
|
token: token,
|
||||||
location: loc,
|
location: loc,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An error from the lexical analysis.
|
/// An error from the lexical analysis.
|
||||||
@@ -76,15 +76,20 @@ pub struct LocatedError {
|
|||||||
/// Wrap up an `Error` with the given location.
|
/// Wrap up an `Error` with the given location.
|
||||||
fn error<'a>(error: Error, loc: Location) -> Result<LocatedToken<'a>, LocatedError> {
|
fn error<'a>(error: Error, loc: Location) -> Result<LocatedToken<'a>, LocatedError> {
|
||||||
Err(LocatedError {
|
Err(LocatedError {
|
||||||
error: error,
|
error: error,
|
||||||
location: loc,
|
location: loc,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the number of decimal digits at the end of `s`.
|
/// Get the number of decimal digits at the end of `s`.
|
||||||
fn trailing_digits(s: &str) -> usize {
|
fn trailing_digits(s: &str) -> usize {
|
||||||
// It's faster to iterate backwards over bytes, and we're only counting ASCII digits.
|
// It's faster to iterate backwards over bytes, and we're only counting ASCII digits.
|
||||||
s.as_bytes().iter().rev().cloned().take_while(|&b| b'0' <= b && b <= b'9').count()
|
s.as_bytes()
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.cloned()
|
||||||
|
.take_while(|&b| b'0' <= b && b <= b'9')
|
||||||
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pre-parse a supposed entity name by splitting it into two parts: A head of lowercase ASCII
|
/// Pre-parse a supposed entity name by splitting it into two parts: A head of lowercase ASCII
|
||||||
@@ -284,9 +289,9 @@ impl<'a> Lexer<'a> {
|
|||||||
// Look for numbered well-known entities like ebb15, v45, ...
|
// Look for numbered well-known entities like ebb15, v45, ...
|
||||||
token(split_entity_name(text)
|
token(split_entity_name(text)
|
||||||
.and_then(|(prefix, number)| {
|
.and_then(|(prefix, number)| {
|
||||||
Self::numbered_entity(prefix, number)
|
Self::numbered_entity(prefix, number)
|
||||||
.or_else(|| Self::value_type(text, prefix, number))
|
.or_else(|| Self::value_type(text, prefix, number))
|
||||||
})
|
})
|
||||||
.unwrap_or(Token::Identifier(text)),
|
.unwrap_or(Token::Identifier(text)),
|
||||||
loc)
|
loc)
|
||||||
}
|
}
|
||||||
@@ -378,39 +383,39 @@ impl<'a> Lexer<'a> {
|
|||||||
loop {
|
loop {
|
||||||
let loc = self.loc();
|
let loc = self.loc();
|
||||||
return match self.lookahead {
|
return match self.lookahead {
|
||||||
None => None,
|
None => None,
|
||||||
Some(';') => Some(self.scan_comment()),
|
Some(';') => Some(self.scan_comment()),
|
||||||
Some('(') => Some(self.scan_char(Token::LPar)),
|
Some('(') => Some(self.scan_char(Token::LPar)),
|
||||||
Some(')') => Some(self.scan_char(Token::RPar)),
|
Some(')') => Some(self.scan_char(Token::RPar)),
|
||||||
Some('{') => Some(self.scan_char(Token::LBrace)),
|
Some('{') => Some(self.scan_char(Token::LBrace)),
|
||||||
Some('}') => Some(self.scan_char(Token::RBrace)),
|
Some('}') => Some(self.scan_char(Token::RBrace)),
|
||||||
Some('[') => Some(self.scan_char(Token::LBracket)),
|
Some('[') => Some(self.scan_char(Token::LBracket)),
|
||||||
Some(']') => Some(self.scan_char(Token::RBracket)),
|
Some(']') => Some(self.scan_char(Token::RBracket)),
|
||||||
Some(',') => Some(self.scan_char(Token::Comma)),
|
Some(',') => Some(self.scan_char(Token::Comma)),
|
||||||
Some('.') => Some(self.scan_char(Token::Dot)),
|
Some('.') => Some(self.scan_char(Token::Dot)),
|
||||||
Some(':') => Some(self.scan_char(Token::Colon)),
|
Some(':') => Some(self.scan_char(Token::Colon)),
|
||||||
Some('=') => Some(self.scan_char(Token::Equal)),
|
Some('=') => Some(self.scan_char(Token::Equal)),
|
||||||
Some('-') => {
|
Some('-') => {
|
||||||
if self.looking_at("->") {
|
if self.looking_at("->") {
|
||||||
Some(self.scan_chars(2, Token::Arrow))
|
Some(self.scan_chars(2, Token::Arrow))
|
||||||
} else {
|
} else {
|
||||||
Some(self.scan_number())
|
Some(self.scan_number())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(ch) if ch.is_digit(10) => Some(self.scan_number()),
|
Some(ch) if ch.is_digit(10) => Some(self.scan_number()),
|
||||||
Some(ch) if ch.is_alphabetic() => Some(self.scan_word()),
|
Some(ch) if ch.is_alphabetic() => Some(self.scan_word()),
|
||||||
Some('%') => Some(self.scan_name()),
|
Some('%') => Some(self.scan_name()),
|
||||||
Some('#') => Some(self.scan_hex_sequence()),
|
Some('#') => Some(self.scan_hex_sequence()),
|
||||||
Some(ch) if ch.is_whitespace() => {
|
Some(ch) if ch.is_whitespace() => {
|
||||||
self.next_ch();
|
self.next_ch();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Skip invalid char, return error.
|
// Skip invalid char, return error.
|
||||||
self.next_ch();
|
self.next_ch();
|
||||||
Some(error(Error::InvalidChar, loc))
|
Some(error(Error::InvalidChar, loc))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,12 @@ use sourcemap::{SourceMap, MutableSourceMap};
|
|||||||
///
|
///
|
||||||
/// Any test commands or ISA declarations are ignored.
|
/// Any test commands or ISA declarations are ignored.
|
||||||
pub fn parse_functions(text: &str) -> Result<Vec<Function>> {
|
pub fn parse_functions(text: &str) -> Result<Vec<Function>> {
|
||||||
parse_test(text).map(|file| file.functions.into_iter().map(|(func, _)| func).collect())
|
parse_test(text).map(|file| {
|
||||||
|
file.functions
|
||||||
|
.into_iter()
|
||||||
|
.map(|(func, _)| func)
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the entire `text` as a test case file.
|
/// Parse the entire `text` as a test case file.
|
||||||
@@ -45,11 +50,11 @@ pub fn parse_test<'a>(text: &'a str) -> Result<TestFile<'a>> {
|
|||||||
let functions = parser.parse_function_list(isa_spec.unique_isa())?;
|
let functions = parser.parse_function_list(isa_spec.unique_isa())?;
|
||||||
|
|
||||||
Ok(TestFile {
|
Ok(TestFile {
|
||||||
commands: commands,
|
commands: commands,
|
||||||
isa_spec: isa_spec,
|
isa_spec: isa_spec,
|
||||||
preamble_comments: preamble_comments,
|
preamble_comments: preamble_comments,
|
||||||
functions: functions,
|
functions: functions,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Parser<'a> {
|
pub struct Parser<'a> {
|
||||||
@@ -114,7 +119,12 @@ impl<'a> Context<'a> {
|
|||||||
|
|
||||||
// Allocate a new signature and add a mapping number -> SigRef.
|
// Allocate a new signature and add a mapping number -> SigRef.
|
||||||
fn add_sig(&mut self, number: u32, data: Signature, loc: &Location) -> Result<()> {
|
fn add_sig(&mut self, number: u32, data: Signature, loc: &Location) -> Result<()> {
|
||||||
self.map.def_sig(number, self.function.dfg.signatures.push(data), loc)
|
self.map.def_sig(number,
|
||||||
|
self.function
|
||||||
|
.dfg
|
||||||
|
.signatures
|
||||||
|
.push(data),
|
||||||
|
loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve a reference to a signature.
|
// Resolve a reference to a signature.
|
||||||
@@ -127,7 +137,12 @@ impl<'a> Context<'a> {
|
|||||||
|
|
||||||
// Allocate a new external function and add a mapping number -> FuncRef.
|
// Allocate a new external function and add a mapping number -> FuncRef.
|
||||||
fn add_fn(&mut self, number: u32, data: ExtFuncData, loc: &Location) -> Result<()> {
|
fn add_fn(&mut self, number: u32, data: ExtFuncData, loc: &Location) -> Result<()> {
|
||||||
self.map.def_fn(number, self.function.dfg.ext_funcs.push(data), loc)
|
self.map.def_fn(number,
|
||||||
|
self.function
|
||||||
|
.dfg
|
||||||
|
.ext_funcs
|
||||||
|
.push(data),
|
||||||
|
loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve a reference to a function.
|
// Resolve a reference to a function.
|
||||||
@@ -269,9 +284,9 @@ impl<'a> Parser<'a> {
|
|||||||
// Gather comments, associate them with `comment_entity`.
|
// Gather comments, associate them with `comment_entity`.
|
||||||
if let Some(entity) = self.comment_entity {
|
if let Some(entity) = self.comment_entity {
|
||||||
self.comments.push(Comment {
|
self.comments.push(Comment {
|
||||||
entity: entity,
|
entity: entity,
|
||||||
text: text,
|
text: text,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => self.lookahead = Some(token),
|
_ => self.lookahead = Some(token),
|
||||||
@@ -777,23 +792,35 @@ impl<'a> Parser<'a> {
|
|||||||
match self.token() {
|
match self.token() {
|
||||||
Some(Token::StackSlot(..)) => {
|
Some(Token::StackSlot(..)) => {
|
||||||
self.gather_comments(ctx.function.stack_slots.next_key());
|
self.gather_comments(ctx.function.stack_slots.next_key());
|
||||||
self.parse_stack_slot_decl()
|
self.parse_stack_slot_decl().and_then(|(num, dat)| {
|
||||||
.and_then(|(num, dat)| ctx.add_ss(num, dat, &self.loc))
|
ctx.add_ss(num, dat, &self.loc)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Some(Token::SigRef(..)) => {
|
Some(Token::SigRef(..)) => {
|
||||||
self.gather_comments(ctx.function.dfg.signatures.next_key());
|
self.gather_comments(ctx.function
|
||||||
self.parse_signature_decl(ctx.unique_isa)
|
.dfg
|
||||||
.and_then(|(num, dat)| ctx.add_sig(num, dat, &self.loc))
|
.signatures
|
||||||
|
.next_key());
|
||||||
|
self.parse_signature_decl(ctx.unique_isa).and_then(|(num, dat)| {
|
||||||
|
ctx.add_sig(num,
|
||||||
|
dat,
|
||||||
|
&self.loc)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Some(Token::FuncRef(..)) => {
|
Some(Token::FuncRef(..)) => {
|
||||||
self.gather_comments(ctx.function.dfg.ext_funcs.next_key());
|
self.gather_comments(ctx.function
|
||||||
self.parse_function_decl(ctx)
|
.dfg
|
||||||
.and_then(|(num, dat)| ctx.add_fn(num, dat, &self.loc))
|
.ext_funcs
|
||||||
|
.next_key());
|
||||||
|
self.parse_function_decl(ctx).and_then(|(num, dat)| {
|
||||||
|
ctx.add_fn(num, dat, &self.loc)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Some(Token::JumpTable(..)) => {
|
Some(Token::JumpTable(..)) => {
|
||||||
self.gather_comments(ctx.function.jump_tables.next_key());
|
self.gather_comments(ctx.function.jump_tables.next_key());
|
||||||
self.parse_jump_table_decl()
|
self.parse_jump_table_decl().and_then(|(num, dat)| {
|
||||||
.and_then(|(num, dat)| ctx.add_jt(num, dat, &self.loc))
|
ctx.add_jt(num, dat, &self.loc)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
// More to come..
|
// More to come..
|
||||||
_ => return Ok(()),
|
_ => return Ok(()),
|
||||||
@@ -852,7 +879,10 @@ impl<'a> Parser<'a> {
|
|||||||
let data = match self.token() {
|
let data = match self.token() {
|
||||||
Some(Token::Identifier("function")) => {
|
Some(Token::Identifier("function")) => {
|
||||||
let (loc, name, sig) = self.parse_function_spec(ctx.unique_isa)?;
|
let (loc, name, sig) = self.parse_function_spec(ctx.unique_isa)?;
|
||||||
let sigref = ctx.function.dfg.signatures.push(sig);
|
let sigref = ctx.function
|
||||||
|
.dfg
|
||||||
|
.signatures
|
||||||
|
.push(sig);
|
||||||
ctx.map.def_entity(sigref.into(), &loc).expect("duplicate SigRef entities created");
|
ctx.map.def_entity(sigref.into(), &loc).expect("duplicate SigRef entities created");
|
||||||
ExtFuncData {
|
ExtFuncData {
|
||||||
name: name,
|
name: name,
|
||||||
@@ -944,11 +974,11 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
// extended-basic-block ::= ebb-header * { instruction }
|
// extended-basic-block ::= ebb-header * { instruction }
|
||||||
while match self.token() {
|
while match self.token() {
|
||||||
Some(Token::Value(_)) => true,
|
Some(Token::Value(_)) => true,
|
||||||
Some(Token::Identifier(_)) => true,
|
Some(Token::Identifier(_)) => true,
|
||||||
Some(Token::LBracket) => true,
|
Some(Token::LBracket) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
} {
|
} {
|
||||||
self.parse_instruction(ctx, ebb)?;
|
self.parse_instruction(ctx, ebb)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1161,7 +1191,10 @@ impl<'a> Parser<'a> {
|
|||||||
ctx.function.dfg.inst_results(inst))?;
|
ctx.function.dfg.inst_results(inst))?;
|
||||||
|
|
||||||
if let Some(result_locations) = result_locations {
|
if let Some(result_locations) = result_locations {
|
||||||
for (value, loc) in ctx.function.dfg.inst_results(inst).zip(result_locations) {
|
for (value, loc) in ctx.function
|
||||||
|
.dfg
|
||||||
|
.inst_results(inst)
|
||||||
|
.zip(result_locations) {
|
||||||
*ctx.function.locations.ensure(value) = loc;
|
*ctx.function.locations.ensure(value) = loc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1197,13 +1230,13 @@ impl<'a> Parser<'a> {
|
|||||||
let ctrl_src_value = inst_data.typevar_operand(&ctx.function.dfg.value_lists)
|
let ctrl_src_value = inst_data.typevar_operand(&ctx.function.dfg.value_lists)
|
||||||
.expect("Constraints <-> Format inconsistency");
|
.expect("Constraints <-> Format inconsistency");
|
||||||
ctx.function.dfg.value_type(match ctx.map.get_value(ctrl_src_value) {
|
ctx.function.dfg.value_type(match ctx.map.get_value(ctrl_src_value) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => {
|
None => {
|
||||||
return err!(self.loc,
|
return err!(self.loc,
|
||||||
"cannot determine type of operand {}",
|
"cannot determine type of operand {}",
|
||||||
ctrl_src_value);
|
ctrl_src_value);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else if constraints.is_polymorphic() {
|
} else if constraints.is_polymorphic() {
|
||||||
// This opcode does not support type inference, so the explicit type variable
|
// This opcode does not support type inference, so the explicit type variable
|
||||||
// is required.
|
// is required.
|
||||||
@@ -1290,7 +1323,7 @@ impl<'a> Parser<'a> {
|
|||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
opcode: Opcode)
|
opcode: Opcode)
|
||||||
-> Result<InstructionData> {
|
-> Result<InstructionData> {
|
||||||
Ok(match opcode.format() {
|
let idata = match opcode.format() {
|
||||||
InstructionFormat::Nullary => {
|
InstructionFormat::Nullary => {
|
||||||
InstructionData::Nullary {
|
InstructionData::Nullary {
|
||||||
opcode: opcode,
|
opcode: opcode,
|
||||||
@@ -1502,7 +1535,8 @@ impl<'a> Parser<'a> {
|
|||||||
table: table,
|
table: table,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
};
|
||||||
|
Ok(idata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1555,8 +1589,8 @@ mod tests {
|
|||||||
ss3 = stack_slot 13
|
ss3 = stack_slot 13
|
||||||
ss1 = stack_slot 1
|
ss1 = stack_slot 1
|
||||||
}")
|
}")
|
||||||
.parse_function(None)
|
.parse_function(None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(func.name.to_string(), "foo");
|
assert_eq!(func.name.to_string(), "foo");
|
||||||
let mut iter = func.stack_slots.keys();
|
let mut iter = func.stack_slots.keys();
|
||||||
let ss0 = iter.next().unwrap();
|
let ss0 = iter.next().unwrap();
|
||||||
@@ -1572,9 +1606,9 @@ mod tests {
|
|||||||
ss1 = stack_slot 13
|
ss1 = stack_slot 13
|
||||||
ss1 = stack_slot 1
|
ss1 = stack_slot 1
|
||||||
}")
|
}")
|
||||||
.parse_function(None)
|
.parse_function(None)
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
"3: duplicate stack slot: ss1");
|
"3: duplicate stack slot: ss1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1584,8 +1618,8 @@ mod tests {
|
|||||||
ebb0:
|
ebb0:
|
||||||
ebb4(vx3: i32):
|
ebb4(vx3: i32):
|
||||||
}")
|
}")
|
||||||
.parse_function(None)
|
.parse_function(None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(func.name.to_string(), "ebbs");
|
assert_eq!(func.name.to_string(), "ebbs");
|
||||||
|
|
||||||
let mut ebbs = func.layout.ebbs();
|
let mut ebbs = func.layout.ebbs();
|
||||||
@@ -1602,8 +1636,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn comments() {
|
fn comments() {
|
||||||
let (func, Details { comments, .. }) =
|
let (func, Details { comments, .. }) = Parser::new("; before
|
||||||
Parser::new("; before
|
|
||||||
function comment() { ; decl
|
function comment() { ; decl
|
||||||
ss10 = stack_slot 13 ; stackslot.
|
ss10 = stack_slot 13 ; stackslot.
|
||||||
; Still stackslot.
|
; Still stackslot.
|
||||||
@@ -1645,7 +1678,7 @@ mod tests {
|
|||||||
set enable_float=false
|
set enable_float=false
|
||||||
; still preamble
|
; still preamble
|
||||||
function comment() {}")
|
function comment() {}")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(tf.commands.len(), 2);
|
assert_eq!(tf.commands.len(), 2);
|
||||||
assert_eq!(tf.commands[0].command, "cfg");
|
assert_eq!(tf.commands[0].command, "cfg");
|
||||||
assert_eq!(tf.commands[1].command, "verify");
|
assert_eq!(tf.commands[1].command, "verify");
|
||||||
@@ -1664,18 +1697,18 @@ mod tests {
|
|||||||
fn isa_spec() {
|
fn isa_spec() {
|
||||||
assert!(parse_test("isa
|
assert!(parse_test("isa
|
||||||
function foo() {}")
|
function foo() {}")
|
||||||
.is_err());
|
.is_err());
|
||||||
|
|
||||||
assert!(parse_test("isa riscv
|
assert!(parse_test("isa riscv
|
||||||
set enable_float=false
|
set enable_float=false
|
||||||
function foo() {}")
|
function foo() {}")
|
||||||
.is_err());
|
.is_err());
|
||||||
|
|
||||||
match parse_test("set enable_float=false
|
match parse_test("set enable_float=false
|
||||||
isa riscv
|
isa riscv
|
||||||
function foo() {}")
|
function foo() {}")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.isa_spec {
|
.isa_spec {
|
||||||
IsaSpec::None(_) => panic!("Expected some ISA"),
|
IsaSpec::None(_) => panic!("Expected some ISA"),
|
||||||
IsaSpec::Some(v) => {
|
IsaSpec::Some(v) => {
|
||||||
assert_eq!(v.len(), 1);
|
assert_eq!(v.len(), 1);
|
||||||
|
|||||||
@@ -63,23 +63,27 @@ impl SourceMap {
|
|||||||
/// Returns the entity reference corresponding to `name`, if it exists.
|
/// Returns the entity reference corresponding to `name`, if it exists.
|
||||||
pub fn lookup_str(&self, name: &str) -> Option<AnyEntity> {
|
pub fn lookup_str(&self, name: &str) -> Option<AnyEntity> {
|
||||||
split_entity_name(name).and_then(|(ent, num)| match ent {
|
split_entity_name(name).and_then(|(ent, num)| match ent {
|
||||||
"v" => {
|
"v" => {
|
||||||
Value::direct_with_number(num)
|
Value::direct_with_number(num)
|
||||||
.and_then(|v| self.get_value(v))
|
.and_then(|v| self.get_value(v))
|
||||||
.map(AnyEntity::Value)
|
.map(AnyEntity::Value)
|
||||||
}
|
}
|
||||||
"vx" => {
|
"vx" => {
|
||||||
Value::table_with_number(num)
|
Value::table_with_number(num)
|
||||||
.and_then(|v| self.get_value(v))
|
.and_then(|v| self.get_value(v))
|
||||||
.map(AnyEntity::Value)
|
.map(AnyEntity::Value)
|
||||||
}
|
}
|
||||||
"ebb" => Ebb::with_number(num).and_then(|e| self.get_ebb(e)).map(AnyEntity::Ebb),
|
"ebb" => {
|
||||||
"ss" => self.get_ss(num).map(AnyEntity::StackSlot),
|
Ebb::with_number(num)
|
||||||
"sig" => self.get_sig(num).map(AnyEntity::SigRef),
|
.and_then(|e| self.get_ebb(e))
|
||||||
"fn" => self.get_fn(num).map(AnyEntity::FuncRef),
|
.map(AnyEntity::Ebb)
|
||||||
"jt" => self.get_jt(num).map(AnyEntity::JumpTable),
|
}
|
||||||
_ => None,
|
"ss" => self.get_ss(num).map(AnyEntity::StackSlot),
|
||||||
})
|
"sig" => self.get_sig(num).map(AnyEntity::SigRef),
|
||||||
|
"fn" => self.get_fn(num).map(AnyEntity::FuncRef),
|
||||||
|
"jt" => self.get_jt(num).map(AnyEntity::JumpTable),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the source location where an entity was defined.
|
/// Get the source location where an entity was defined.
|
||||||
@@ -229,7 +233,7 @@ mod tests {
|
|||||||
ebb0(v4: i32, vx7: i32):
|
ebb0(v4: i32, vx7: i32):
|
||||||
v10 = iadd v4, vx7
|
v10 = iadd v4, vx7
|
||||||
}")
|
}")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let map = &tf.functions[0].1.map;
|
let map = &tf.functions[0].1.map;
|
||||||
|
|
||||||
assert_eq!(map.lookup_str("v0"), None);
|
assert_eq!(map.lookup_str("v0"), None);
|
||||||
|
|||||||
Reference in New Issue
Block a user