Most of the way to no_std support

This commit is contained in:
Lachlan Sneff
2018-01-15 14:05:38 -05:00
committed by Dan Gohman
parent 2a26b70854
commit 7375088c3e
42 changed files with 146 additions and 5 deletions

View File

@@ -17,3 +17,11 @@ name = "cretonne"
# Please don't add any unless they are essential to the task of creating binary
# machine code. Integration tests that need external dependencies can be
# accomodated in `tests`.
[dependencies.hashmap_core]
version = "0.1.1"
optional = true
[features]
# Currently, the only feature is the `no_std` feature.
# Enabling this disables use of `stdlib`.
no_std = ["hashmap_core"]

View File

@@ -5,6 +5,7 @@
use ir::{ArgumentLoc, AbiParam, ArgumentExtension, Type};
use std::cmp::Ordering;
use std::vec::Vec;
/// Legalization action to perform on a single argument or return value when converting a
/// signature.

View File

@@ -10,12 +10,17 @@
/// thread doing the logging.
use std::cell::RefCell;
#[cfg(not(feature = "no_std"))]
use std::env;
#[cfg(not(feature = "no_std"))]
use std::ffi::OsStr;
use std::fmt;
#[cfg(not(feature = "no_std"))]
use std::fs::File;
#[cfg(not(feature = "no_std"))]
use std::io::{self, Write};
use std::sync::atomic;
#[cfg(not(feature = "no_std"))]
use std::thread;
static STATE: atomic::AtomicIsize = atomic::ATOMIC_ISIZE_INIT;
@@ -26,6 +31,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(not(feature = "no_std"))]
#[inline]
pub fn enabled() -> bool {
if cfg!(debug_assertions) {
@@ -38,7 +44,15 @@ pub fn enabled() -> bool {
}
}
/// Does nothing
#[cfg(feature = "no_std")]
#[inline]
pub fn enabled() -> bool {
false
}
/// Initialize `STATE` from the environment variable.
#[cfg(not(feature = "no_std"))]
fn initialize() -> bool {
let enable = match env::var_os("CRETONNE_DBG") {
Some(s) => s != OsStr::new("0"),
@@ -54,6 +68,7 @@ fn initialize() -> bool {
enable
}
#[cfg(not(feature = "no_std"))]
thread_local! {
static WRITER : RefCell<io::BufWriter<File>> = RefCell::new(open_file());
}
@@ -61,6 +76,7 @@ thread_local! {
/// Write a line with the given format arguments.
///
/// This is for use by the `dbg!` macro.
#[cfg(not(feature = "no_std"))]
pub fn writeln_with_format_args(args: fmt::Arguments) -> io::Result<()> {
WRITER.with(|rc| {
let mut w = rc.borrow_mut();
@@ -70,6 +86,7 @@ pub fn writeln_with_format_args(args: fmt::Arguments) -> io::Result<()> {
}
/// Open the tracing file for the current thread.
#[cfg(not(feature = "no_std"))]
fn open_file() -> io::BufWriter<File> {
let curthread = thread::current();
let tmpstr;
@@ -97,6 +114,7 @@ macro_rules! dbg {
if $crate::dbg::enabled() {
// Drop the error result so we don't get compiler errors for ignoring it.
// What are you going to do, log the error?
#[cfg(not(feature = "no_std"))]
$crate::dbg::writeln_with_format_args(format_args!($($arg)+)).ok();
}
}

View File

@@ -10,6 +10,7 @@ use std::mem;
use timing;
use std::cmp::Ordering;
use std::vec::Vec;
// RPO numbers are not first assigned in a contiguous way but as multiples of STRIDE, to leave
// room for modifications of the dominator tree.

View File

@@ -3,6 +3,7 @@ use entity::EntityRef;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
use std::vec::Vec;
/// A small list of entity references allocated from a pool.
///

View File

@@ -3,6 +3,7 @@
use entity::{EntityRef, Keys};
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
use std::vec::Vec;
/// A mapping `K -> V` for densely indexed entity references.
///

View File

@@ -2,6 +2,7 @@
use entity::{EntityRef, Keys};
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
use std::vec::Vec;
/// A primary mapping `K -> V` allocating dense entity references.
///

View File

@@ -2,6 +2,7 @@
use entity::{EntityRef, Keys};
use std::marker::PhantomData;
use std::vec::Vec;
/// A set of `K` for densely indexed entity references.
///

View File

@@ -11,6 +11,7 @@ use entity::{EntityRef, EntityMap};
use std::mem;
use std::slice;
use std::u32;
use std::vec::Vec;
/// Trait for extracting keys from values stored in a `SparseMap`.
///

View File

@@ -10,6 +10,7 @@ use isa::{RegInfo, RegUnit};
use std::cmp;
use std::fmt;
use std::str::FromStr;
use std::vec::Vec;
/// Function signature.
///

View File

@@ -9,6 +9,7 @@
use std::fmt::{self, Display, Formatter};
use std::str::FromStr;
use std::ops::{Deref, DerefMut};
use std::vec::Vec;
use ir;
use ir::{Value, Type, Ebb, JumpTable, SigRef, FuncRef, StackSlot, MemFlags};

View File

@@ -8,6 +8,7 @@ use ir::entities::Ebb;
use std::iter;
use std::slice;
use std::fmt::{self, Display, Formatter};
use std::vec::Vec;
/// Contents of a jump table.
///

View File

@@ -10,6 +10,7 @@ use std::cmp;
use std::fmt;
use std::ops::{Index, IndexMut};
use std::str::FromStr;
use std::vec::Vec;
/// The size of an object on the stack, or the size of a stack frame.
///

View File

@@ -15,6 +15,8 @@ use ir;
use regalloc;
use std::fmt;
use std::boxed::Box;
#[allow(dead_code)]
struct Isa {
shared_flags: shared_settings::Flags,

View File

@@ -15,6 +15,8 @@ use ir;
use regalloc;
use std::fmt;
use std::boxed::Box;
#[allow(dead_code)]
struct Isa {
shared_flags: shared_settings::Flags,

View File

@@ -17,6 +17,7 @@ use result;
use timing;
use std::fmt;
use std::boxed::Box;
#[allow(dead_code)]
struct Isa {

View File

@@ -55,6 +55,8 @@ use timing;
use isa::enc_tables::Encodings;
use std::fmt;
use std::boxed::Box;
#[cfg(build_riscv)]
mod riscv;

View File

@@ -15,6 +15,8 @@ use ir;
use regalloc;
use std::fmt;
use std::boxed::Box;
#[allow(dead_code)]
struct Isa {
shared_flags: shared_settings::Flags,

View File

@@ -25,6 +25,7 @@ use ir::{Function, DataFlowGraph, Inst, InstBuilder, Ebb, Type, Value, Signature
use ir::instructions::CallInfo;
use isa::TargetIsa;
use legalizer::split::{isplit, vsplit};
use std::vec::Vec;
/// Legalize all the function signatures in `func`.
///

View File

@@ -15,7 +15,7 @@ pub fn expand_as_libcall(inst: ir::Inst, func: &mut ir::Function) -> bool {
let funcref = find_funcref(libcall, func).unwrap_or_else(|| make_funcref(libcall, inst, func));
// Now we convert `inst` to a call. First save the arguments.
let mut args = Vec::new();
let mut args = vec![];
args.extend_from_slice(func.dfg.inst_args(inst));
// The replace builder will preserve the instruction result values.
func.dfg.replace(inst).call(funcref, &args);

View File

@@ -68,6 +68,7 @@ use cursor::{Cursor, CursorPosition, FuncCursor};
use flowgraph::ControlFlowGraph;
use ir::{self, Ebb, Inst, Value, Type, Opcode, ValueDef, InstructionData, InstBuilder};
use std::iter;
use std::vec::Vec;
/// Split `value` into two values using the `isplit` semantics. Do this by reusing existing values
/// if possible.

View File

@@ -1,7 +1,17 @@
//! Cretonne code generation library.
#![cfg_attr(feature = "no_std", no_std)]
#![deny(missing_docs)]
// Turns on alloc feature if no_std
#![cfg_attr(feature = "no_std", feature(alloc))]
// Include the `hashmap_core` crate if no_std
#[cfg(feature = "no_std")]
extern crate hashmap_core;
#[cfg(feature = "no_std")]
#[macro_use]
extern crate alloc;
pub use context::Context;
pub use legalizer::legalize_function;
pub use verifier::verify_function;
@@ -46,3 +56,25 @@ mod stack_layout;
mod topo_order;
mod unreachable_code;
mod write;
/// This replaces `std` in builds with no_std.
#[cfg(feature = "no_std")]
mod std {
pub use core::*;
#[macro_use]
pub use alloc::{boxed, vec, string};
pub mod prelude {
pub use core::prelude as v1;
}
pub mod collections {
pub use hashmap_core::{HashMap, HashSet};
pub use hashmap_core::map as hash_map;
pub use alloc::BTreeSet;
}
pub mod error {
pub trait Error {
fn description(&self) -> &str;
fn cause(&self) -> Option<&Error> { None }
}
}
}

View File

@@ -8,6 +8,7 @@ use dominator_tree::DominatorTree;
use entity::{EntityList, ListPool};
use loop_analysis::{Loop, LoopAnalysis};
use timing;
use std::vec::Vec;
/// Performs the LICM pass by detecting loops within the CFG and moving
/// loop-invariant instructions out of them.

View File

@@ -8,6 +8,7 @@ use flowgraph::ControlFlowGraph;
use ir::{Function, Ebb, Layout};
use packed_option::PackedOption;
use timing;
use std::vec::Vec;
/// A opaque reference to a code loop.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]

View File

@@ -18,6 +18,9 @@ use std::cmp;
use std::iter;
use std::fmt;
use std::slice;
use std::iter::Peekable;
use std::mem;
use std::vec::Vec;
use isa::{TargetIsa, EncInfo};
use timing;

View File

@@ -11,6 +11,7 @@ use ir::{Value, ValueLoc, ValueLocations, StackSlot};
use ir::{InstructionData, Opcode};
use isa::{RegUnit, RegInfo};
use std::fmt;
use std::vec::Vec;
/// A diversion of a value from its original location to a new register or stack location.
///

View File

@@ -13,6 +13,7 @@ use regalloc::affinity::Affinity;
use regalloc::liveness::Liveness;
use regalloc::liverange::LiveRange;
use std::collections::HashMap;
use std::vec::Vec;
type ValueList = EntityList<Value>;

View File

@@ -184,6 +184,7 @@ use regalloc::affinity::Affinity;
use regalloc::liverange::{LiveRange, LiveRangeForest, LiveRangeContext};
use std::mem;
use std::ops::Index;
use std::vec::Vec;
use timing;
/// A set of live ranges, indexed by value number.

View File

@@ -21,6 +21,7 @@ use regalloc::live_value_tracker::{LiveValue, LiveValueTracker};
use regalloc::liveness::Liveness;
use timing;
use topo_order::TopoOrder;
use std::vec::Vec;
/// Reusable data structures for the reload pass.
pub struct Reload {

View File

@@ -108,6 +108,7 @@ use std::fmt;
use std::mem;
use super::AllocatableSet;
use std::u16;
use std::vec::Vec;
/// A variable in the constraint problem.
///

View File

@@ -26,6 +26,7 @@ use regalloc::liveness::Liveness;
use regalloc::pressure::Pressure;
use regalloc::virtregs::VirtRegs;
use std::fmt;
use std::vec::Vec;
use timing;
use topo_order::TopoOrder;

View File

@@ -24,6 +24,7 @@ use constant_hash::{probe, simple_hash};
use isa::TargetIsa;
use std::fmt;
use std::result;
use std::vec::Vec;
/// A string-based configurator for settings groups.
///

View File

@@ -7,6 +7,9 @@ use ir::{InstructionData, Function, Inst, Opcode, Type};
use scoped_hash_map::ScopedHashMap;
use timing;
#[cfg(feature = "no_std")]
use alloc::Vec;
/// Test whether the given opcode is unsafe to even consider for GVN.
fn trivially_unsafe_for_gvn(opcode: Opcode) -> bool {
opcode.is_call() || opcode.is_branch() || opcode.is_terminator() ||

View File

@@ -87,12 +87,12 @@ impl fmt::Display for Pass {
}
}
/// Implementation details.
///
/// 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` functions.
#[cfg(not(feature = "no_std"))]
mod details {
use super::{Pass, NUM_PASSES, DESCRIPTIONS};
use std::cell::{Cell, RefCell};
@@ -214,6 +214,27 @@ mod details {
}
}
/// Dummy `debug` implementation
#[cfg(feature = "no_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::*;

View File

@@ -4,6 +4,9 @@ use entity::SparseSet;
use dominator_tree::DominatorTree;
use ir::{Ebb, Layout};
#[cfg(feature = "no_std")]
use alloc::Vec;
/// Present EBBs in a topological order such that all dominating EBBs are guaranteed to be visited
/// before the current EBB.
///

View File

@@ -73,6 +73,8 @@ use std::collections::BTreeSet;
use std::error as std_error;
use std::fmt::{self, Display, Formatter, Write};
use std::result;
use std::vec::Vec;
use std::string::String;
use timing;
pub use self::cssa::verify_cssa;

View File

@@ -9,6 +9,7 @@ use isa::{TargetIsa, RegInfo};
use std::fmt::{self, Result, Error, Write};
use std::result;
use packed_option::ReservedValue;
use std::string::String;
/// Write `func` to `w` as equivalent text.
/// Use `isa` to emit ISA-dependent annotations.

View File

@@ -13,3 +13,6 @@ name = "cton_frontend"
[dependencies]
cretonne = { path = "../cretonne", version = "0.1.0" }
[features]
no_std = ["cretonne/no_std"]

View File

@@ -142,11 +142,23 @@
//! }
//! ```
#![cfg_attr(feature = "no_std", no_std)]
#![deny(missing_docs)]
#![cfg_attr(feature = "no_std", feature(alloc))]
extern crate cretonne;
#[cfg(feature = "no_std")]
extern crate alloc;
pub use frontend::{ILBuilder, FunctionBuilder};
mod frontend;
mod ssa;
#[cfg(feature = "no_std")]
mod std {
pub use alloc::vec;
pub use core::*;
}

View File

@@ -15,6 +15,7 @@ use std::u32;
use cretonne::ir::types::{F32, F64};
use cretonne::ir::immediates::{Ieee32, Ieee64};
use std::mem;
use std::vec::Vec;
/// Structure containing the data relevant the construction of SSA for a given function.
///

View File

@@ -15,3 +15,6 @@ cretonne = { path = "../cretonne", version = "0.1.0" }
[target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dependencies]
raw-cpuid = "3.0.0"
[features]
no_std = ["cretonne/no_std"]

View File

@@ -1,6 +1,6 @@
//! Performs autodetection of the host for the purposes of running
//! Cretonne to generate code to run on the same machine.
#![cfg_attr(feature = "no_std", no_std)]
#![deny(missing_docs)]
extern crate cretonne;