Use PackedOption<Ebb> to represent jump tables.
Avoid NO_EBB.
This commit is contained in:
@@ -3,7 +3,8 @@
|
|||||||
//! Jump tables are declared in the preamble and assigned an `ir::entities::JumpTable` reference.
|
//! Jump tables are declared in the preamble and assigned an `ir::entities::JumpTable` reference.
|
||||||
//! The actual table of destinations is stored in a `JumpTableData` struct defined in this module.
|
//! The actual table of destinations is stored in a `JumpTableData` struct defined in this module.
|
||||||
|
|
||||||
use ir::entities::{Ebb, NO_EBB};
|
use packed_option::PackedOption;
|
||||||
|
use ir::entities::Ebb;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
@@ -14,10 +15,10 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
/// to be completely populated, though. Individual entries can be missing.
|
/// to be completely populated, though. Individual entries can be missing.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct JumpTableData {
|
pub struct JumpTableData {
|
||||||
// Table entries, using NO_EBB as a placeholder for missing entries.
|
// Table entries, using `None` as a placeholder for missing entries.
|
||||||
table: Vec<Ebb>,
|
table: Vec<PackedOption<Ebb>>,
|
||||||
|
|
||||||
// How many `NO_EBB` holes in table?
|
// How many `None` holes in table?
|
||||||
holes: usize,
|
holes: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,16 +35,15 @@ impl JumpTableData {
|
|||||||
///
|
///
|
||||||
/// The table will grow as needed to fit 'idx'.
|
/// The table will grow as needed to fit 'idx'.
|
||||||
pub fn set_entry(&mut self, idx: usize, dest: Ebb) {
|
pub fn set_entry(&mut self, idx: usize, dest: Ebb) {
|
||||||
assert!(dest != NO_EBB);
|
|
||||||
// Resize table to fit `idx`.
|
// Resize table to fit `idx`.
|
||||||
if idx >= self.table.len() {
|
if idx >= self.table.len() {
|
||||||
self.holes += idx - self.table.len();
|
self.holes += idx - self.table.len();
|
||||||
self.table.resize(idx + 1, NO_EBB);
|
self.table.resize(idx + 1, None.into());
|
||||||
} else if self.table[idx] == NO_EBB {
|
} else if self.table[idx].is_none() {
|
||||||
// We're filling in an existing hole.
|
// We're filling in an existing hole.
|
||||||
self.holes -= 1;
|
self.holes -= 1;
|
||||||
}
|
}
|
||||||
self.table[idx] = dest;
|
self.table[idx] = dest.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear a table entry.
|
/// Clear a table entry.
|
||||||
@@ -51,19 +51,15 @@ impl JumpTableData {
|
|||||||
/// The `br_table` instruction will fall through if given an index corresponding to a cleared
|
/// The `br_table` instruction will fall through if given an index corresponding to a cleared
|
||||||
/// table entry.
|
/// table entry.
|
||||||
pub fn clear_entry(&mut self, idx: usize) {
|
pub fn clear_entry(&mut self, idx: usize) {
|
||||||
if idx < self.table.len() && self.table[idx] != NO_EBB {
|
if idx < self.table.len() && self.table[idx].is_some() {
|
||||||
self.holes += 1;
|
self.holes += 1;
|
||||||
self.table[idx] = NO_EBB;
|
self.table[idx] = None.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the entry for `idx`, or `None`.
|
/// Get the entry for `idx`, or `None`.
|
||||||
pub fn get_entry(&self, idx: usize) -> Option<Ebb> {
|
pub fn get_entry(&self, idx: usize) -> Option<Ebb> {
|
||||||
if idx < self.table.len() && self.table[idx] != NO_EBB {
|
self.table.get(idx).and_then(|e| e.expand())
|
||||||
Some(self.table[idx])
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enumerate over all `(idx, dest)` pairs in the table in order.
|
/// Enumerate over all `(idx, dest)` pairs in the table in order.
|
||||||
@@ -74,13 +70,13 @@ impl JumpTableData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Access the whole table as a mutable slice.
|
/// Access the whole table as a mutable slice.
|
||||||
pub fn as_mut_slice(&mut self) -> &mut [Ebb] {
|
pub fn as_mut_slice(&mut self) -> &mut [PackedOption<Ebb>] {
|
||||||
self.table.as_mut_slice()
|
self.table.as_mut_slice()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enumerate `(idx, dest)` pairs in order.
|
/// Enumerate `(idx, dest)` pairs in order.
|
||||||
pub struct Entries<'a>(iter::Enumerate<iter::Cloned<slice::Iter<'a, Ebb>>>);
|
pub struct Entries<'a>(iter::Enumerate<iter::Cloned<slice::Iter<'a, PackedOption<Ebb>>>>);
|
||||||
|
|
||||||
impl<'a> Iterator for Entries<'a> {
|
impl<'a> Iterator for Entries<'a> {
|
||||||
type Item = (usize, Ebb);
|
type Item = (usize, Ebb);
|
||||||
@@ -88,8 +84,8 @@ impl<'a> Iterator for Entries<'a> {
|
|||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
loop {
|
loop {
|
||||||
if let Some((idx, dest)) = self.0.next() {
|
if let Some((idx, dest)) = self.0.next() {
|
||||||
if dest != NO_EBB {
|
if let Some(ebb) = dest.expand() {
|
||||||
return Some((idx, dest));
|
return Some((idx, ebb));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
@@ -100,18 +96,15 @@ impl<'a> Iterator for Entries<'a> {
|
|||||||
|
|
||||||
impl Display for JumpTableData {
|
impl Display for JumpTableData {
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||||
let first = self.table.first().cloned().unwrap_or_default();
|
match self.table.first().and_then(|e| e.expand()) {
|
||||||
if first == NO_EBB {
|
None => try!(write!(fmt, "jump_table 0")),
|
||||||
try!(write!(fmt, "jump_table 0"));
|
Some(first) => try!(write!(fmt, "jump_table {}", first)),
|
||||||
} else {
|
|
||||||
try!(write!(fmt, "jump_table {}", first));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for dest in self.table.iter().cloned().skip(1) {
|
for dest in self.table.iter().skip(1).map(|e| e.expand()) {
|
||||||
if dest == NO_EBB {
|
match dest {
|
||||||
try!(write!(fmt, ", 0"));
|
None => try!(write!(fmt, ", 0")),
|
||||||
} else {
|
Some(ebb) => try!(write!(fmt, ", {}", ebb)),
|
||||||
try!(write!(fmt, ", {}", dest));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ impl<T: ReservedValue> PackedOption<T> {
|
|||||||
self.0 == T::reserved_value()
|
self.0 == T::reserved_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the packed option is a `Some` value.
|
||||||
|
pub fn is_some(&self) -> bool {
|
||||||
|
!self.is_none()
|
||||||
|
}
|
||||||
|
|
||||||
/// Expand the packed option into a normal `Option`.
|
/// Expand the packed option into a normal `Option`.
|
||||||
pub fn expand(self) -> Option<T> {
|
pub fn expand(self) -> Option<T> {
|
||||||
if self.is_none() { None } else { Some(self.0) }
|
if self.is_none() { None } else { Some(self.0) }
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use cretonne::ir::{Function, Ebb, Opcode, Value, Type, FunctionName, StackSlotDa
|
|||||||
FuncRef};
|
FuncRef};
|
||||||
use cretonne::ir::types::VOID;
|
use cretonne::ir::types::VOID;
|
||||||
use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64};
|
use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64};
|
||||||
use cretonne::ir::entities::{AnyEntity, NO_EBB, NO_INST, NO_VALUE};
|
use cretonne::ir::entities::{AnyEntity, NO_INST, NO_VALUE};
|
||||||
use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs,
|
use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs,
|
||||||
TernaryOverflowData, JumpData, BranchData, CallData,
|
TernaryOverflowData, JumpData, BranchData, CallData,
|
||||||
IndirectCallData, ReturnData};
|
IndirectCallData, ReturnData};
|
||||||
@@ -204,9 +204,11 @@ impl Context {
|
|||||||
// Rewrite EBB references in jump tables.
|
// Rewrite EBB references in jump tables.
|
||||||
for jt in self.function.jump_tables.keys() {
|
for jt in self.function.jump_tables.keys() {
|
||||||
let loc = jt.into();
|
let loc = jt.into();
|
||||||
for ebb in self.function.jump_tables[jt].as_mut_slice() {
|
for ebb_ref in self.function.jump_tables[jt].as_mut_slice() {
|
||||||
if *ebb != NO_EBB {
|
if let Some(mut ebb) = ebb_ref.expand() {
|
||||||
try!(self.map.rewrite_ebb(ebb, loc));
|
try!(self.map.rewrite_ebb(&mut ebb, loc));
|
||||||
|
// Convert back to a packed option.
|
||||||
|
*ebb_ref = ebb.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user