Merge pull request #303 from sunfishcode/no_std_merge
Merge no_std into master
This commit is contained in:
@@ -3,6 +3,10 @@
|
||||
use super::{Comparator, Forest, Node, NodeData, NodePool, Path, INNER_SIZE};
|
||||
use packed_option::PackedOption;
|
||||
use std::marker::PhantomData;
|
||||
#[cfg(test)]
|
||||
use std::fmt;
|
||||
#[cfg(test)]
|
||||
use std::string::String;
|
||||
|
||||
/// Tag type defining forest types for a map.
|
||||
struct MapTypes<K, V, C>(PhantomData<(K, V, C)>);
|
||||
@@ -207,14 +211,14 @@ where
|
||||
#[cfg(test)]
|
||||
impl<K, V, C> Map<K, V, C>
|
||||
where
|
||||
K: Copy + ::std::fmt::Display,
|
||||
K: Copy + fmt::Display,
|
||||
V: Copy,
|
||||
C: Comparator<K>,
|
||||
{
|
||||
/// Verify consistency.
|
||||
fn verify(&self, forest: &MapForest<K, V, C>, comp: &C)
|
||||
where
|
||||
NodeData<MapTypes<K, V, C>>: ::std::fmt::Display,
|
||||
NodeData<MapTypes<K, V, C>>: fmt::Display,
|
||||
{
|
||||
if let Some(root) = self.root.expand() {
|
||||
forest.nodes.verify_tree(root, comp);
|
||||
@@ -223,6 +227,7 @@ where
|
||||
|
||||
/// Get a text version of the path to `key`.
|
||||
fn tpath(&self, key: K, forest: &MapForest<K, V, C>, comp: &C) -> String {
|
||||
use std::string::ToString;
|
||||
match self.root.expand() {
|
||||
None => "map(empty)".to_string(),
|
||||
Some(root) => {
|
||||
@@ -405,8 +410,8 @@ where
|
||||
#[cfg(test)]
|
||||
impl<'a, K, V, C> MapCursor<'a, K, V, C>
|
||||
where
|
||||
K: Copy + ::std::fmt::Display,
|
||||
V: Copy + ::std::fmt::Display,
|
||||
K: Copy + fmt::Display,
|
||||
V: Copy + fmt::Display,
|
||||
C: Comparator<K>,
|
||||
{
|
||||
fn verify(&self) {
|
||||
@@ -416,6 +421,7 @@ where
|
||||
|
||||
/// Get a text version of the path to the current position.
|
||||
fn tpath(&self) -> String {
|
||||
use std::string::ToString;
|
||||
self.path.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
use super::{Forest, Node, NodeData};
|
||||
use entity::PrimaryMap;
|
||||
use std::ops::{Index, IndexMut};
|
||||
#[cfg(test)]
|
||||
use std::fmt;
|
||||
|
||||
/// A pool of nodes, including a free list.
|
||||
pub(super) struct NodePool<F: Forest> {
|
||||
@@ -74,8 +76,8 @@ impl<F: Forest> NodePool<F> {
|
||||
/// Verify the consistency of the tree rooted at `node`.
|
||||
pub fn verify_tree(&self, node: Node, comp: &F::Comparator)
|
||||
where
|
||||
NodeData<F>: ::std::fmt::Display,
|
||||
F::Key: ::std::fmt::Display,
|
||||
NodeData<F>: fmt::Display,
|
||||
F::Key: fmt::Display,
|
||||
{
|
||||
use super::Comparator;
|
||||
use entity::SparseSet;
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
use super::{Comparator, Forest, Node, NodeData, NodePool, Path, SetValue, INNER_SIZE};
|
||||
use packed_option::PackedOption;
|
||||
use std::marker::PhantomData;
|
||||
#[cfg(test)]
|
||||
use std::fmt;
|
||||
#[cfg(test)]
|
||||
use std::string::String;
|
||||
|
||||
/// Tag type defining forest types for a set.
|
||||
struct SetTypes<K, C>(PhantomData<(K, C)>);
|
||||
@@ -305,7 +309,7 @@ where
|
||||
#[cfg(test)]
|
||||
impl<'a, K, C> SetCursor<'a, K, C>
|
||||
where
|
||||
K: Copy + ::std::fmt::Display,
|
||||
K: Copy + fmt::Display,
|
||||
C: Comparator<K>,
|
||||
{
|
||||
fn verify(&self) {
|
||||
@@ -315,6 +319,7 @@ where
|
||||
|
||||
/// Get a text version of the path to the current position.
|
||||
fn tpath(&self) -> String {
|
||||
use std::string::ToString;
|
||||
self.path.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ use preopt::do_preopt;
|
||||
use regalloc;
|
||||
use result::{CtonError, CtonResult};
|
||||
use settings::{FlagsOrIsa, OptLevel};
|
||||
use std::vec::Vec;
|
||||
use simple_gvn::do_simple_gvn;
|
||||
use timing;
|
||||
use unreachable_code::eliminate_unreachable_code;
|
||||
|
||||
@@ -8,15 +8,23 @@
|
||||
///
|
||||
/// The output will appear in files named `cretonne.dbg.*`, where the suffix is named after the
|
||||
/// thread doing the logging.
|
||||
#[cfg(feature = "std")]
|
||||
use std::cell::RefCell;
|
||||
#[cfg(feature = "std")]
|
||||
use std::env;
|
||||
#[cfg(feature = "std")]
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt;
|
||||
#[cfg(feature = "std")]
|
||||
use std::fs::File;
|
||||
#[cfg(feature = "std")]
|
||||
use std::io::{self, Write};
|
||||
#[cfg(feature = "std")]
|
||||
use std::sync::atomic;
|
||||
#[cfg(feature = "std")]
|
||||
use std::thread;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
static STATE: atomic::AtomicIsize = atomic::ATOMIC_ISIZE_INIT;
|
||||
|
||||
/// Is debug tracing enabled?
|
||||
@@ -25,6 +33,7 @@ static STATE: atomic::AtomicIsize = atomic::ATOMIC_ISIZE_INIT;
|
||||
/// other than `0`.
|
||||
///
|
||||
/// This inline function turns into a constant `false` when debug assertions are disabled.
|
||||
#[cfg(feature = "std")]
|
||||
#[inline]
|
||||
pub fn enabled() -> bool {
|
||||
if cfg!(debug_assertions) {
|
||||
@@ -37,7 +46,15 @@ pub fn enabled() -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Does nothing
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[inline]
|
||||
pub fn enabled() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Initialize `STATE` from the environment variable.
|
||||
#[cfg(feature = "std")]
|
||||
fn initialize() -> bool {
|
||||
let enable = match env::var_os("CRETONNE_DBG") {
|
||||
Some(s) => s != OsStr::new("0"),
|
||||
@@ -53,6 +70,7 @@ fn initialize() -> bool {
|
||||
enable
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
thread_local! {
|
||||
static WRITER : RefCell<io::BufWriter<File>> = RefCell::new(open_file());
|
||||
}
|
||||
@@ -60,6 +78,7 @@ thread_local! {
|
||||
/// Write a line with the given format arguments.
|
||||
///
|
||||
/// This is for use by the `dbg!` macro.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn writeln_with_format_args(args: fmt::Arguments) -> io::Result<()> {
|
||||
WRITER.with(|rc| {
|
||||
let mut w = rc.borrow_mut();
|
||||
@@ -69,6 +88,7 @@ pub fn writeln_with_format_args(args: fmt::Arguments) -> io::Result<()> {
|
||||
}
|
||||
|
||||
/// Open the tracing file for the current thread.
|
||||
#[cfg(feature = "std")]
|
||||
fn open_file() -> io::BufWriter<File> {
|
||||
let curthread = thread::current();
|
||||
let tmpstr;
|
||||
@@ -90,6 +110,7 @@ fn open_file() -> io::BufWriter<File> {
|
||||
/// Write a line to the debug trace file if tracing is enabled.
|
||||
///
|
||||
/// Arguments are the same as for `printf!`.
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_export]
|
||||
macro_rules! dbg {
|
||||
($($arg:tt)+) => {
|
||||
@@ -101,6 +122,13 @@ macro_rules! dbg {
|
||||
}
|
||||
}
|
||||
|
||||
/// `dbg!` isn't supported in `no_std` mode, so expand it into nothing.
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[macro_export]
|
||||
macro_rules! dbg {
|
||||
($($arg:tt)+) => {}
|
||||
}
|
||||
|
||||
/// Helper for printing lists.
|
||||
pub struct DisplayList<'a, T>(pub &'a [T])
|
||||
where
|
||||
|
||||
@@ -121,6 +121,7 @@ mod tests {
|
||||
use super::ExternalName;
|
||||
use ir::LibCall;
|
||||
use std::string::ToString;
|
||||
use std::u32;
|
||||
|
||||
#[test]
|
||||
fn display_testcase() {
|
||||
@@ -143,7 +144,7 @@ mod tests {
|
||||
assert_eq!(ExternalName::user(0, 0).to_string(), "u0:0");
|
||||
assert_eq!(ExternalName::user(1, 1).to_string(), "u1:1");
|
||||
assert_eq!(
|
||||
ExternalName::user(::std::u32::MAX, ::std::u32::MAX).to_string(),
|
||||
ExternalName::user(u32::MAX, u32::MAX).to_string(),
|
||||
"u4294967295:4294967295"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use ir;
|
||||
use ir::InstBuilder;
|
||||
use std::vec::Vec;
|
||||
|
||||
/// Try to expand `inst` as a library call, returning true is successful.
|
||||
pub fn expand_as_libcall(inst: ir::Inst, func: &mut ir::Function) -> bool {
|
||||
|
||||
@@ -41,6 +41,21 @@
|
||||
use_self,
|
||||
))]
|
||||
|
||||
// Turns on no_std and alloc features if std is not available.
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
||||
|
||||
// Include the `hashmap_core` crate if std is not available.
|
||||
#[allow(unused_extern_crates)]
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate hashmap_core;
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
extern crate failure;
|
||||
#[macro_use]
|
||||
extern crate failure_derive;
|
||||
|
||||
pub use context::Context;
|
||||
pub use legalizer::legalize_function;
|
||||
pub use verifier::verify_function;
|
||||
@@ -93,3 +108,15 @@ mod stack_layout;
|
||||
mod topo_order;
|
||||
mod unreachable_code;
|
||||
mod write;
|
||||
|
||||
/// This replaces `std` in builds with `core`.
|
||||
#[cfg(not(feature = "std"))]
|
||||
mod std {
|
||||
pub use core::*;
|
||||
pub use alloc::{boxed, vec, string};
|
||||
pub mod collections {
|
||||
pub use hashmap_core::{HashMap, HashSet};
|
||||
pub use hashmap_core::map as hash_map;
|
||||
pub use alloc::BTreeSet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ use ir;
|
||||
use isa::TargetIsa;
|
||||
use result::CtonError;
|
||||
use std::fmt::Write;
|
||||
use std::string::{String, ToString};
|
||||
use verifier;
|
||||
|
||||
/// Pretty-print a verifier error.
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
//! Result and error types representing the outcome of compiling a function.
|
||||
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
use verifier;
|
||||
|
||||
/// A compilation error.
|
||||
///
|
||||
/// When Cretonne fails to compile a function, it will return one of these error codes.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Fail, Debug, PartialEq, Eq)]
|
||||
pub enum CtonError {
|
||||
/// The input is invalid.
|
||||
///
|
||||
/// This error code is used by a WebAssembly translator when it encounters invalid WebAssembly
|
||||
/// code. This should never happen for validated WebAssembly code.
|
||||
#[fail(display = "Invalid input code")]
|
||||
InvalidInput,
|
||||
|
||||
/// An IR verifier error.
|
||||
///
|
||||
/// This always represents a bug, either in the code that generated IR for Cretonne, or a bug
|
||||
/// in Cretonne itself.
|
||||
Verifier(verifier::Error),
|
||||
#[fail(display = "Verifier error: {}", _0)]
|
||||
Verifier(
|
||||
#[cause]
|
||||
verifier::Error
|
||||
),
|
||||
|
||||
/// An implementation limit was exceeded.
|
||||
///
|
||||
@@ -27,48 +30,20 @@ pub enum CtonError {
|
||||
/// limits][limits] that cause compilation to fail when they are exceeded.
|
||||
///
|
||||
/// [limits]: https://cretonne.readthedocs.io/en/latest/langref.html#implementation-limits
|
||||
#[fail(display = "Implementation limit exceeded")]
|
||||
ImplLimitExceeded,
|
||||
|
||||
/// The code size for the function is too large.
|
||||
///
|
||||
/// Different target ISAs may impose a limit on the size of a compiled function. If that limit
|
||||
/// is exceeded, compilation fails.
|
||||
#[fail(display = "Code for function is too large")]
|
||||
CodeTooLarge,
|
||||
}
|
||||
|
||||
/// A Cretonne compilation result.
|
||||
pub type CtonResult = Result<(), CtonError>;
|
||||
|
||||
impl fmt::Display for CtonError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
CtonError::Verifier(ref e) => write!(f, "Verifier error: {}", e),
|
||||
CtonError::InvalidInput |
|
||||
CtonError::ImplLimitExceeded |
|
||||
CtonError::CodeTooLarge => f.write_str(self.description()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for CtonError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
CtonError::InvalidInput => "Invalid input code",
|
||||
CtonError::Verifier(ref e) => &e.message,
|
||||
CtonError::ImplLimitExceeded => "Implementation limit exceeded",
|
||||
CtonError::CodeTooLarge => "Code for function is too large",
|
||||
}
|
||||
}
|
||||
fn cause(&self) -> Option<&StdError> {
|
||||
match *self {
|
||||
CtonError::Verifier(ref e) => Some(e),
|
||||
CtonError::InvalidInput |
|
||||
CtonError::ImplLimitExceeded |
|
||||
CtonError::CodeTooLarge => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<verifier::Error> for CtonError {
|
||||
fn from(e: verifier::Error) -> Self {
|
||||
CtonError::Verifier(e)
|
||||
|
||||
@@ -94,7 +94,8 @@ impl fmt::Display for Pass {
|
||||
///
|
||||
/// This whole module can be gated on a `cfg` feature to provide a dummy implementation for
|
||||
/// performance-sensitive builds or restricted environments. The dummy implementation must provide
|
||||
/// `TimingToken` and `PassTimings` types and a `take_current` function.
|
||||
/// `TimingToken` and `PassTimes` types and `take_current`, `add_to_current`, and `start_pass` funcs
|
||||
#[cfg(feature = "std")]
|
||||
mod details {
|
||||
use super::{Pass, DESCRIPTIONS, NUM_PASSES};
|
||||
use std::cell::{Cell, RefCell};
|
||||
@@ -216,9 +217,31 @@ mod details {
|
||||
}
|
||||
}
|
||||
|
||||
/// Dummy `debug` implementation
|
||||
#[cfg(not(feature = "std"))]
|
||||
mod details {
|
||||
use super::Pass;
|
||||
/// Dummy `TimingToken`
|
||||
pub struct TimingToken;
|
||||
/// Dummy `PassTimes`
|
||||
pub struct PassTimes;
|
||||
/// Returns dummy `PassTimes`
|
||||
pub fn take_current() -> PassTimes {
|
||||
PassTimes
|
||||
}
|
||||
/// does nothing
|
||||
pub fn add_to_current(_times: PassTimes) {}
|
||||
|
||||
/// does nothing
|
||||
pub(super) fn start_pass(_pass: Pass) -> TimingToken {
|
||||
TimingToken
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::string::ToString;
|
||||
|
||||
#[test]
|
||||
fn display() {
|
||||
|
||||
@@ -70,7 +70,6 @@ use iterators::IteratorExtras;
|
||||
use settings::{Flags, FlagsOrIsa};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeSet;
|
||||
use std::error as std_error;
|
||||
use std::fmt::{self, Display, Formatter, Write};
|
||||
use std::result;
|
||||
use std::string::String;
|
||||
@@ -104,7 +103,7 @@ mod liveness;
|
||||
mod locations;
|
||||
|
||||
/// A verifier error.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Fail, Debug, PartialEq, Eq)]
|
||||
pub struct Error {
|
||||
/// The entity causing the verifier error.
|
||||
pub location: AnyEntity,
|
||||
@@ -118,12 +117,6 @@ impl Display for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl std_error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
&self.message
|
||||
}
|
||||
}
|
||||
|
||||
/// Verifier result.
|
||||
pub type Result = result::Result<(), Error>;
|
||||
|
||||
@@ -1166,10 +1159,13 @@ mod tests {
|
||||
Ok(_) => panic!("Expected an error"),
|
||||
Err(Error { message, .. }) => {
|
||||
if !message.contains($msg) {
|
||||
#[cfg(feature = "std")]
|
||||
panic!(format!(
|
||||
"'{}' did not contain the substring '{}'",
|
||||
message, $msg
|
||||
));
|
||||
#[cfg(not(feature = "std"))]
|
||||
panic!("error message did not contain the expected substring");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user