Skip to content

Commit

Permalink
Fixes bytecodealliance#13: Enable conditional compilation of ISAs thr…
Browse files Browse the repository at this point in the history
…ough features;
  • Loading branch information
bnjbvr authored and sunfishcode committed Feb 12, 2019
1 parent eac36a9 commit 2145dd3
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 90 deletions.
10 changes: 9 additions & 1 deletion cranelift-codegen/Cargo.toml
Expand Up @@ -29,16 +29,24 @@ log = { version = "0.4.6", default-features = false }
cranelift-codegen-meta = { path = "meta", version = "0.28.0" }

[features]
default = ["std", "x86", "arm32", "arm64", "riscv"]

# The "std" feature enables use of libstd. The "core" feature enables use
# of some minimal std-like replacement libraries. At least one of these two
# features need to be enabled.
default = ["std"]
std = ["cranelift-entity/std", "cranelift-bforest/std", "target-lexicon/std"]
core = ["hashmap_core"]

# This enables some additional functions useful for writing tests, but which
# can significantly increase the size of the library.
testing_hooks = []

# ISA targets for which we should build.
x86 = []
arm32 = []
arm64 = []
riscv = []

[badges]
maintenance = { status = "experimental" }
travis-ci = { repository = "CraneStation/cranelift" }
36 changes: 17 additions & 19 deletions cranelift-codegen/build.rs
Expand Up @@ -11,10 +11,6 @@
// TARGET
// Target triple provided by Cargo.
//
// CRANELIFT_TARGETS (Optional)
// A setting for conditional compilation of isa targets. Possible values can be "native" or
// known isa targets separated by ','.
//
// The build script expects to be run from the directory where this build.rs file lives. The
// current directory is used to find the sources.

Expand All @@ -31,22 +27,24 @@ fn main() {
let target_triple = env::var("TARGET").expect("The TARGET environment variable must be set");

// Configure isa targets cfg.
let cranelift_targets = env::var("CRANELIFT_TARGETS").ok();
let cranelift_targets = cranelift_targets
.as_ref()
.map(|s| s.as_ref())
.filter(|s: &&str| s.len() > 0);

let isas = match cranelift_targets {
Some("native") => meta::isa_from_arch(&target_triple.split('-').next().unwrap()),
Some(targets) => meta::isas_from_targets(targets.split(',').collect::<Vec<_>>()),
None => meta::all_isas(),
}
.expect("Error when identifying CRANELIFT_TARGETS and TARGET");
let isa_targets = meta::isa::Isa::all()
.into_iter()
.cloned()
.filter(|isa| {
let env_key = format!("CARGO_FEATURE_{}", isa.to_string().to_uppercase());
env::var(env_key).is_ok()
})
.collect::<Vec<_>>();

for isa in &isas {
println!("cargo:rustc-cfg=build_{}", isa.to_string());
}
let isas = if isa_targets.is_empty() {
// Try to match native target.
let target_name = target_triple.split('-').next().unwrap();
let isa = meta::isa_from_arch(&target_name).expect("error when identifying target");
println!("cargo:rustc-cfg=feature=\"{}\"", isa);
vec![isa]
} else {
isa_targets
};

let cur_dir = env::current_dir().expect("Can't access current working directory");
let crate_dir = cur_dir.as_path();
Expand Down
1 change: 1 addition & 0 deletions cranelift-codegen/meta/src/isa/mod.rs
Expand Up @@ -44,6 +44,7 @@ impl Isa {
}

impl fmt::Display for Isa {
// These names should be kept in sync with the crate features.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Isa::Riscv => write!(f, "riscv"),
Expand Down
39 changes: 2 additions & 37 deletions cranelift-codegen/meta/src/lib.rs
Expand Up @@ -13,43 +13,8 @@ mod shared;
mod srcgen;
mod unique_table;

pub fn isa_from_arch(arch: &str) -> Result<Vec<isa::Isa>, String> {
isa::Isa::from_arch(arch)
.ok_or_else(|| format!("no supported isa found for arch `{}`", arch))
.and_then(|isa| Ok(vec![isa]))
}

pub fn isas_from_targets(targets: Vec<&str>) -> Result<Vec<isa::Isa>, String> {
type R<'a> = Vec<(&'a str, Option<isa::Isa>)>;

let (known, unknown): (R, R) = targets
.into_iter()
.map(|target| (target, isa::Isa::from_name(target)))
.partition(|(_, opt_isa)| opt_isa.is_some());

if !unknown.is_empty() {
let unknown_targets = unknown
.into_iter()
.map(|(target, _)| target)
.collect::<Vec<_>>()
.join(", ");
return Err(format!("unknown isa targets: {}", unknown_targets));
}

let isas = if known.is_empty() {
isa::Isa::all().to_vec()
} else {
known
.into_iter()
.map(|(_, opt_isa)| opt_isa.unwrap())
.collect()
};

Ok(isas)
}

pub fn all_isas() -> Result<Vec<isa::Isa>, String> {
isas_from_targets(vec![])
pub fn isa_from_arch(arch: &str) -> Result<isa::Isa, String> {
isa::Isa::from_arch(arch).ok_or_else(|| format!("no supported isa found for arch `{}`", arch))
}

/// Generates all the Rust source files used in Cranelift from the meta-language.
Expand Down
24 changes: 12 additions & 12 deletions cranelift-codegen/src/isa/mod.rs
Expand Up @@ -68,16 +68,16 @@ use failure_derive::Fail;
use std::boxed::Box;
use target_lexicon::{Architecture, PointerWidth, Triple};

#[cfg(build_riscv)]
#[cfg(feature = "riscv")]
mod riscv;

#[cfg(build_x86)]
#[cfg(feature = "x86")]
mod x86;

#[cfg(build_arm32)]
#[cfg(feature = "arm32")]
mod arm32;

#[cfg(build_arm64)]
#[cfg(feature = "arm64")]
mod arm64;

mod call_conv;
Expand All @@ -90,12 +90,12 @@ mod stack;
/// Returns a builder that can create a corresponding `TargetIsa`
/// or `Err(LookupError::Unsupported)` if not enabled.
macro_rules! isa_builder {
($module:ident, $name:ident) => {{
#[cfg($name)]
($name:ident, $feature:tt) => {{
#[cfg(feature = $feature)]
fn $name(triple: Triple) -> Result<Builder, LookupError> {
Ok($module::isa_builder(triple))
Ok($name::isa_builder(triple))
};
#[cfg(not($name))]
#[cfg(not(feature = $feature))]
fn $name(_triple: Triple) -> Result<Builder, LookupError> {
Err(LookupError::Unsupported)
}
Expand All @@ -107,9 +107,9 @@ macro_rules! isa_builder {
/// Return a builder that can create a corresponding `TargetIsa`.
pub fn lookup(triple: Triple) -> Result<Builder, LookupError> {
match triple.architecture {
Architecture::Riscv32 | Architecture::Riscv64 => isa_builder!(riscv, build_riscv)(triple),
Architecture::Riscv32 | Architecture::Riscv64 => isa_builder!(riscv, "riscv")(triple),
Architecture::I386 | Architecture::I586 | Architecture::I686 | Architecture::X86_64 => {
isa_builder!(x86, build_x86)(triple)
isa_builder!(x86, "x86")(triple)
}
Architecture::Thumbv6m
| Architecture::Thumbv7em
Expand All @@ -118,8 +118,8 @@ pub fn lookup(triple: Triple) -> Result<Builder, LookupError> {
| Architecture::Armv4t
| Architecture::Armv5te
| Architecture::Armv7
| Architecture::Armv7s => isa_builder!(arm32, build_arm32)(triple),
Architecture::Aarch64 => isa_builder!(arm64, build_arm64)(triple),
| Architecture::Armv7s => isa_builder!(arm32, "arm32")(triple),
Architecture::Aarch64 => isa_builder!(arm64, "arm64")(triple),
_ => Err(LookupError::Unsupported),
}
}
Expand Down
2 changes: 1 addition & 1 deletion cranelift-codegen/src/regalloc/pressure.rs
Expand Up @@ -270,7 +270,7 @@ impl fmt::Display for Pressure {
}

#[cfg(test)]
#[cfg(build_arm32)]
#[cfg(feature = "arm32")]
mod tests {
use super::Pressure;
use crate::isa::{RegClass, TargetIsa};
Expand Down
2 changes: 1 addition & 1 deletion cranelift-codegen/src/regalloc/solver.rs
Expand Up @@ -1127,7 +1127,7 @@ impl fmt::Display for Solver {
}

#[cfg(test)]
#[cfg(build_arm32)]
#[cfg(feature = "arm32")]
mod tests {
use super::{Move, Solver};
use crate::entity::EntityRef;
Expand Down
2 changes: 1 addition & 1 deletion cranelift-filetests/src/runner.rs
Expand Up @@ -83,7 +83,7 @@ pub struct TestRunner {
}

impl TestRunner {
/// Create a new blank TrstRunner.
/// Create a new blank TestRunner.
pub fn new(verbose: bool, report_times: bool) -> Self {
Self {
verbose,
Expand Down
16 changes: 15 additions & 1 deletion cranelift-filetests/src/runone.rs
Expand Up @@ -33,7 +33,21 @@ pub fn run(path: &Path, passes: Option<&[String]>, target: Option<&str>) -> Test
info!("---\nFile: {}", path.to_string_lossy());
let started = time::Instant::now();
let buffer = read_to_string(path).map_err(|e| e.to_string())?;
let testfile = parse_test(&buffer, passes, target).map_err(|e| e.to_string())?;

let testfile = match parse_test(&buffer, passes, target) {
Ok(testfile) => testfile,
Err(e) => {
if e.is_warning {
println!(
"skipping test {:?} (line {}): {}",
path, e.location.line_number, e.message
);
return Ok(started.elapsed());
}
return Err(e.to_string());
}
};

if testfile.functions.is_empty() {
return Err("no functions found".to_string());
}
Expand Down
14 changes: 14 additions & 0 deletions cranelift-reader/src/error.rs
Expand Up @@ -19,6 +19,8 @@ pub struct ParseError {
pub location: Location,
/// Error message.
pub message: String,
/// Whether it's a warning or a plain error.
pub is_warning: bool,
}

impl fmt::Display for ParseError {
Expand All @@ -40,13 +42,25 @@ macro_rules! err {
Err($crate::ParseError {
location: $loc.clone(),
message: $msg.to_string(),
is_warning: false,
})
};

( $loc:expr, $fmt:expr, $( $arg:expr ),+ ) => {
Err($crate::ParseError {
location: $loc.clone(),
message: format!( $fmt, $( $arg ),+ ),
is_warning: false,
})
};
}

macro_rules! warn {
( $loc:expr, $fmt:expr, $( $arg:expr ),+ ) => {
Err($crate::ParseError {
location: $loc.clone(),
message: format!($fmt, $( $arg ),+ ),
is_warning: true,
})
};
}
2 changes: 1 addition & 1 deletion cranelift-reader/src/isaspec.rs
Expand Up @@ -17,7 +17,7 @@ pub enum IsaSpec {
/// which are reflected in the finished `Flags` object.
None(Flags),

/// The parsed file does contains `isa` commands.
/// The parsed file does contain `isa` commands.
/// Each `isa` command is used to configure a `TargetIsa` trait object.
Some(Vec<Box<TargetIsa>>),
}
Expand Down

0 comments on commit 2145dd3

Please sign in to comment.