Allow both x86 backends to be included, selected with a "variant" flag. (#2514)

This PR adds a new `isa::lookup_variant()` that takes a `BackendVariant`
(`Legacy`, `MachInst` or `Any`), and exposes both x86 backends as
separate variants if both are compiled into the build.

This will allow some new use-cases that require both backends in the
same process: for example, differential fuzzing between old and new
backends, or perhaps allowing for dynamic feature-flag selection between
the backends.
This commit is contained in:
Chris Fallin
2020-12-16 07:56:04 -08:00
committed by GitHub
parent 245abc2bb2
commit e91987c43c
4 changed files with 67 additions and 32 deletions

View File

@@ -75,10 +75,13 @@ use thiserror::Error;
#[cfg(feature = "riscv")] #[cfg(feature = "riscv")]
mod riscv; mod riscv;
// Exclude the old x86 backend when the new one is enabled; it is unreachable // N.B.: the old x86-64 backend (`x86`) and the new one (`x64`) can both be
// anyway (requesting the x86-64 ISA will return the new backend), and a number // included; if the new backend is included, then it is the default backend
// of old-backend-specific tests fail. // returned for an x86-64 triple, but a specific option can request the old
#[cfg(all(feature = "x86", not(feature = "x64")))] // backend. It is important to have the ability to instantiate *both* backends
// in the same build so that we can do things like differential fuzzing between
// backends, or perhaps offer a runtime configuration flag in the future.
#[cfg(feature = "x86")]
mod x86; mod x86;
#[cfg(feature = "x64")] #[cfg(feature = "x64")]
@@ -117,24 +120,56 @@ macro_rules! isa_builder {
}}; }};
} }
/// The "variant" for a given target. On one platform (x86-64), we have two
/// backends, the "old" and "new" one; the new one is the default if included
/// in the build configuration and not otherwise specified.
#[derive(Clone, Copy)]
pub enum BackendVariant {
/// Any backend available.
Any,
/// A "legacy" backend: one that operates using legalizations and encodings.
Legacy,
/// A backend built on `MachInst`s and the `VCode` framework.
MachInst,
}
impl Default for BackendVariant {
fn default() -> Self {
BackendVariant::Any
}
}
/// Look for an ISA for the given `triple`, selecting the backend variant given
/// by `variant` if available.
pub fn lookup_variant(triple: Triple, variant: BackendVariant) -> Result<Builder, LookupError> {
match (triple.architecture, variant) {
(Architecture::Riscv32 { .. }, _) | (Architecture::Riscv64 { .. }, _) => {
isa_builder!(riscv, (feature = "riscv"), triple)
}
(Architecture::X86_64, BackendVariant::Legacy) => {
isa_builder!(x86, (feature = "x86"), triple)
}
(Architecture::X86_64, BackendVariant::MachInst) => {
isa_builder!(x64, (feature = "x64"), triple)
}
#[cfg(feature = "x64")]
(Architecture::X86_64, BackendVariant::Any) => {
isa_builder!(x64, (feature = "x64"), triple)
}
#[cfg(not(feature = "x64"))]
(Architecture::X86_64, BackendVariant::Any) => {
isa_builder!(x86, (feature = "x86"), triple)
}
(Architecture::Arm { .. }, _) => isa_builder!(arm32, (feature = "arm32"), triple),
(Architecture::Aarch64 { .. }, _) => isa_builder!(aarch64, (feature = "arm64"), triple),
_ => Err(LookupError::Unsupported),
}
}
/// Look for an ISA for the given `triple`. /// Look for an ISA for the given `triple`.
/// Return a builder that can create a corresponding `TargetIsa`. /// Return a builder that can create a corresponding `TargetIsa`.
pub fn lookup(triple: Triple) -> Result<Builder, LookupError> { pub fn lookup(triple: Triple) -> Result<Builder, LookupError> {
match triple.architecture { lookup_variant(triple, BackendVariant::Any)
Architecture::Riscv32 { .. } | Architecture::Riscv64 { .. } => {
isa_builder!(riscv, (feature = "riscv"), triple)
}
Architecture::X86_32 { .. } | Architecture::X86_64 => {
if cfg!(feature = "x64") {
isa_builder!(x64, (feature = "x64"), triple)
} else {
isa_builder!(x86, (all(feature = "x86", not(feature = "x64"))), triple)
}
}
Architecture::Arm { .. } => isa_builder!(arm32, (feature = "arm32"), triple),
Architecture::Aarch64 { .. } => isa_builder!(aarch64, (feature = "arm64"), triple),
_ => Err(LookupError::Unsupported),
}
} }
/// Look for a supported ISA with the given `name`. /// Look for a supported ISA with the given `name`.

View File

@@ -250,7 +250,7 @@ mod tests {
use crate::ir::{ use crate::ir::{
types, AbiParam, ExternalName, InstBuilder, Signature, StackSlotData, StackSlotKind, types, AbiParam, ExternalName, InstBuilder, Signature, StackSlotData, StackSlotKind,
}; };
use crate::isa::{lookup, CallConv}; use crate::isa::{lookup_variant, BackendVariant, CallConv};
use crate::settings::{builder, Flags}; use crate::settings::{builder, Flags};
use crate::Context; use crate::Context;
use std::str::FromStr; use std::str::FromStr;
@@ -258,7 +258,7 @@ mod tests {
#[test] #[test]
fn test_small_alloc() { fn test_small_alloc() {
let isa = lookup(triple!("x86_64")) let isa = lookup_variant(triple!("x86_64"), BackendVariant::Legacy)
.expect("expect x86 ISA") .expect("expect x86 ISA")
.finish(Flags::new(builder())); .finish(Flags::new(builder()));
@@ -314,7 +314,7 @@ mod tests {
#[test] #[test]
fn test_medium_alloc() { fn test_medium_alloc() {
let isa = lookup(triple!("x86_64")) let isa = lookup_variant(triple!("x86_64"), BackendVariant::Legacy)
.expect("expect x86 ISA") .expect("expect x86 ISA")
.finish(Flags::new(builder())); .finish(Flags::new(builder()));
@@ -370,7 +370,7 @@ mod tests {
#[test] #[test]
fn test_large_alloc() { fn test_large_alloc() {
let isa = lookup(triple!("x86_64")) let isa = lookup_variant(triple!("x86_64"), BackendVariant::Legacy)
.expect("expect x86 ISA") .expect("expect x86 ISA")
.finish(Flags::new(builder())); .finish(Flags::new(builder()));
@@ -442,7 +442,7 @@ mod tests {
#[test] #[test]
fn test_multi_return_func() { fn test_multi_return_func() {
let isa = lookup(triple!("x86_64")) let isa = lookup_variant(triple!("x86_64"), BackendVariant::Legacy)
.expect("expect x86 ISA") .expect("expect x86 ISA")
.finish(Flags::new(builder())); .finish(Flags::new(builder()));

View File

@@ -134,7 +134,7 @@ mod tests {
use crate::ir::{ use crate::ir::{
types, AbiParam, ExternalName, InstBuilder, Signature, StackSlotData, StackSlotKind, types, AbiParam, ExternalName, InstBuilder, Signature, StackSlotData, StackSlotKind,
}; };
use crate::isa::{lookup, CallConv}; use crate::isa::{lookup_variant, BackendVariant, CallConv};
use crate::settings::{builder, Flags}; use crate::settings::{builder, Flags};
use crate::Context; use crate::Context;
use gimli::write::Address; use gimli::write::Address;
@@ -143,7 +143,7 @@ mod tests {
#[test] #[test]
fn test_simple_func() { fn test_simple_func() {
let isa = lookup(triple!("x86_64")) let isa = lookup_variant(triple!("x86_64"), BackendVariant::Legacy)
.expect("expect x86 ISA") .expect("expect x86 ISA")
.finish(Flags::new(builder())); .finish(Flags::new(builder()));
@@ -185,7 +185,7 @@ mod tests {
#[test] #[test]
fn test_multi_return_func() { fn test_multi_return_func() {
let isa = lookup(triple!("x86_64")) let isa = lookup_variant(triple!("x86_64"), BackendVariant::Legacy)
.expect("expect x86 ISA") .expect("expect x86 ISA")
.finish(Flags::new(builder())); .finish(Flags::new(builder()));

View File

@@ -46,7 +46,7 @@ mod tests {
use crate::ir::{ExternalName, InstBuilder, Signature, StackSlotData, StackSlotKind}; use crate::ir::{ExternalName, InstBuilder, Signature, StackSlotData, StackSlotKind};
use crate::isa::unwind::winx64::UnwindCode; use crate::isa::unwind::winx64::UnwindCode;
use crate::isa::x86::registers::RU; use crate::isa::x86::registers::RU;
use crate::isa::{lookup, CallConv}; use crate::isa::{lookup_variant, BackendVariant, CallConv};
use crate::settings::{builder, Flags}; use crate::settings::{builder, Flags};
use crate::Context; use crate::Context;
use std::str::FromStr; use std::str::FromStr;
@@ -54,7 +54,7 @@ mod tests {
#[test] #[test]
fn test_wrong_calling_convention() { fn test_wrong_calling_convention() {
let isa = lookup(triple!("x86_64")) let isa = lookup_variant(triple!("x86_64"), BackendVariant::Legacy)
.expect("expect x86 ISA") .expect("expect x86 ISA")
.finish(Flags::new(builder())); .finish(Flags::new(builder()));
@@ -70,7 +70,7 @@ mod tests {
#[test] #[test]
fn test_small_alloc() { fn test_small_alloc() {
let isa = lookup(triple!("x86_64")) let isa = lookup_variant(triple!("x86_64"), BackendVariant::Legacy)
.expect("expect x86 ISA") .expect("expect x86 ISA")
.finish(Flags::new(builder())); .finish(Flags::new(builder()));
@@ -127,7 +127,7 @@ mod tests {
#[test] #[test]
fn test_medium_alloc() { fn test_medium_alloc() {
let isa = lookup(triple!("x86_64")) let isa = lookup_variant(triple!("x86_64"), BackendVariant::Legacy)
.expect("expect x86 ISA") .expect("expect x86 ISA")
.finish(Flags::new(builder())); .finish(Flags::new(builder()));
@@ -188,7 +188,7 @@ mod tests {
#[test] #[test]
fn test_large_alloc() { fn test_large_alloc() {
let isa = lookup(triple!("x86_64")) let isa = lookup_variant(triple!("x86_64"), BackendVariant::Legacy)
.expect("expect x86 ISA") .expect("expect x86 ISA")
.finish(Flags::new(builder())); .finish(Flags::new(builder()));