Merge pull request #303 from sunfishcode/no_std_merge

Merge no_std into master
This commit is contained in:
Dan Gohman
2018-04-20 12:11:53 -07:00
committed by GitHub
26 changed files with 318 additions and 74 deletions

View File

@@ -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()
}
}

View File

@@ -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;

View File

@@ -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()
}
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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"
);
}

View File

@@ -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 {

View File

@@ -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;
}
}

View File

@@ -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.

View File

@@ -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)

View File

@@ -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() {

View File

@@ -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");
}
}
}