Skip to content

Commit

Permalink
Bug 1618595: Support Cranelift's new codegen backend in Baldrdash; r=…
Browse files Browse the repository at this point in the history
…cfallin

And enable it for aarch64.

Differential Revision: https://phabricator.services.mozilla.com/D69997
  • Loading branch information
bnjbvr committed Apr 30, 2020
1 parent 034dfbf commit f0e5de2
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 90 deletions.
2 changes: 1 addition & 1 deletion js/src/jit-test/tests/wasm/gc/disabled.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const { CompileError, validate } = WebAssembly;

const UNRECOGNIZED_OPCODE_OR_BAD_TYPE = /unrecognized opcode|(Structure|reference) types not enabled|invalid inline block type|bad type/;
const UNRECOGNIZED_OPCODE_OR_BAD_TYPE = /unrecognized opcode|(Structure|reference) types not enabled|invalid inline block type|bad type|Cranelift error in clifFunc/;

let simpleTests = [
"(module (func (drop (ref.null))))",
Expand Down
8 changes: 1 addition & 7 deletions js/src/wasm/WasmCraneliftCompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,7 @@ using namespace js;
using namespace js::jit;
using namespace js::wasm;

bool wasm::CraneliftPlatformSupport() {
#ifdef JS_CODEGEN_X64
return true;
#else
return false;
#endif
}
bool wasm::CraneliftPlatformSupport() { return cranelift_supports_platform(); }

static inline SymbolicAddress ToSymbolicAddress(BD_SymbolicAddress bd) {
switch (bd) {
Expand Down
4 changes: 4 additions & 0 deletions js/src/wasm/cranelift/clifapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
struct CraneliftCompiler;

extern "C" {

// Returns true if the platform is supported by Cranelift.
bool cranelift_supports_platform();

// A static initializer, that must be called only once.
void cranelift_initialize();

Expand Down
115 changes: 79 additions & 36 deletions js/src/wasm/cranelift/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use cranelift_codegen::Context;
use cranelift_wasm::{FuncIndex, FuncTranslator, ModuleTranslationState, WasmResult};

use crate::bindings;
use crate::isa::{make_isa, POINTER_SIZE};
use crate::isa::make_isa;
use crate::utils::DashResult;
use crate::wasm2clif::{init_sig, TransEnv, TRAP_THROW_REPORTED};

Expand Down Expand Up @@ -221,7 +221,12 @@ impl<'static_env, 'module_env> BatchCompiler<'static_env, 'module_env> {
}

if self.static_environ.ref_types_enabled {
self.emit_stackmaps(stackmaps);
if self.context.mach_compile_result.is_some() {
// TODO Bug 1633721: new backend: support stackmaps.
log::warn!("new isel backend doesn't support stackmaps yet");
} else {
self.emit_stackmaps(stackmaps);
}
}

self.current_func.code_size = info.code_size;
Expand Down Expand Up @@ -262,15 +267,20 @@ impl<'static_env, 'module_env> BatchCompiler<'static_env, 'module_env> {
fn frame_pushed(&self) -> StackSize {
// Cranelift computes the total stack frame size including the pushed return address,
// standard SM prologue pushes, and its own stack slots.
let total = self
.context
.func
.stack_slots
.layout_info
.expect("No frame")
.frame_size;
let total = if let Some(result) = &self.context.mach_compile_result {
result.frame_size
} else {
self.context
.func
.stack_slots
.layout_info
.expect("No frame")
.frame_size
};

let sm_pushed = StackSize::from(self.isa.flags().baldrdash_prologue_words())
* mem::size_of::<usize>() as StackSize;

total
.checked_sub(sm_pushed)
.expect("SpiderMonkey prologue pushes not counted")
Expand Down Expand Up @@ -346,16 +356,33 @@ impl<'a> RelocSink for Relocations<'a> {
index,
} => {
// A simple function call to another wasm function.
let payload_size = match reloc {
Reloc::X86CallPCRel4 => 4,
_ => panic!("unhandled call relocation"),
let func_index = FuncIndex::new(index as usize);

// On x86, the Spidermonkey relocation must point to the next instruction.
// Cranelift gives us the exact offset to the immediate, so fix it up by the
// relocation's size.
#[cfg(feature = "cranelift_x86")]
let offset = at
+ match reloc {
Reloc::X86CallPCRel4 => 4,
_ => unreachable!(),
};

// Spidermonkey Aarch64 requires the relocation to point just after the start of
// the actual relocation, for historical reasons.
#[cfg(feature = "cranelift_arm64")]
let offset = match reloc {
Reloc::Arm64Call => at + 4,
_ => unreachable!(),
};

let func_index = FuncIndex::new(index as usize);
#[cfg(not(any(feature = "cranelift_x86", feature = "cranelift_arm64")))]
let offset = {
// Avoid warning about unused relocation.
let _reloc = reloc;
at
};

// The Spidermonkey relocation must point to the next instruction. Cranelift gives
// us the exact offset to the immediate, so fix it up by the relocation's size.
let offset = at + payload_size;
self.metadata.push(bindings::MetadataEntry::direct_call(
offset, srcloc, func_index,
));
Expand All @@ -365,33 +392,33 @@ impl<'a> RelocSink for Relocations<'a> {
namespace: SYMBOLIC_FUNCTION_NAMESPACE,
index,
} => {
let payload_size = match reloc {
Reloc::Abs8 => {
debug_assert_eq!(POINTER_SIZE, 8);
8
}
_ => panic!("unhandled user-space symbolic call relocation"),
};

// This is a symbolic function reference encoded by `symbolic_function_name()`.
let sym = index.into();

// The Spidermonkey relocation must point to the next instruction.
let offset = at + payload_size;
// See comments about offsets in the User match arm above.

#[cfg(feature = "cranelift_x86")]
let offset = at
+ match reloc {
Reloc::Abs8 => 8,
_ => unreachable!(),
};

#[cfg(feature = "cranelift_arm64")]
let offset = match reloc {
Reloc::Abs8 => at + 4,
_ => unreachable!(),
};

#[cfg(not(any(feature = "cranelift_x86", feature = "cranelift_arm64")))]
let offset = at;

self.metadata.push(bindings::MetadataEntry::symbolic_access(
offset, srcloc, sym,
));
}

ExternalName::LibCall(call) => {
let payload_size = match reloc {
Reloc::Abs8 => {
debug_assert_eq!(POINTER_SIZE, 8);
8
}
_ => panic!("unhandled libcall symbolic call relocation"),
};

let sym = match call {
ir::LibCall::CeilF32 => bindings::SymbolicAddress::CeilF32,
ir::LibCall::CeilF64 => bindings::SymbolicAddress::CeilF64,
Expand All @@ -406,8 +433,24 @@ impl<'a> RelocSink for Relocations<'a> {
}
};

// The Spidermonkey relocation must point to the next instruction.
let offset = at + payload_size;
// The Spidermonkey relocation must point to the next instruction, on x86.
#[cfg(feature = "cranelift_x86")]
let offset = at
+ match reloc {
Reloc::Abs8 => 8,
_ => unreachable!(),
};

// Spidermonkey AArch64 doesn't expect a relocation offset, in this case.
#[cfg(feature = "cranelift_arm64")]
let offset = match reloc {
Reloc::Abs8 => at,
_ => unreachable!(),
};

#[cfg(not(any(feature = "cranelift_x86", feature = "cranelift_arm64")))]
let offset = at;

self.metadata.push(bindings::MetadataEntry::symbolic_access(
offset, srcloc, sym,
));
Expand Down
115 changes: 71 additions & 44 deletions js/src/wasm/cranelift/src/isa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,74 @@ pub const POINTER_SIZE: usize = 8;
#[cfg(target_pointer_width = "32")]
pub const POINTER_SIZE: usize = 4;

#[cfg(feature = "cranelift_x86")]
pub mod platform {
use super::*;

pub const IS_SUPPORTED: bool = true;
pub const USES_HEAP_REG: bool = true;

pub fn make_isa_builder(env: &StaticEnvironment) -> DashResult<isa::Builder> {
let mut ib = isa::lookup_by_name("x86_64-unknown-unknown").map_err(BasicError::from)?;

if !env.has_sse2 {
return Err("SSE2 is mandatory for Baldrdash!".into());
}

if env.has_sse3 {
ib.enable("has_sse3").map_err(BasicError::from)?;
}
if env.has_sse41 {
ib.enable("has_sse41").map_err(BasicError::from)?;
}
if env.has_sse42 {
ib.enable("has_sse42").map_err(BasicError::from)?;
}
if env.has_popcnt {
ib.enable("has_popcnt").map_err(BasicError::from)?;
}
if env.has_avx {
ib.enable("has_avx").map_err(BasicError::from)?;
}
if env.has_bmi1 {
ib.enable("has_bmi1").map_err(BasicError::from)?;
}
if env.has_bmi2 {
ib.enable("has_bmi2").map_err(BasicError::from)?;
}
if env.has_lzcnt {
ib.enable("has_lzcnt").map_err(BasicError::from)?;
}

Ok(ib)
}
}

#[cfg(feature = "cranelift_arm64")]
pub mod platform {
use super::*;

pub const IS_SUPPORTED: bool = true;
pub const USES_HEAP_REG: bool = true;

pub fn make_isa_builder(_env: &StaticEnvironment) -> DashResult<isa::Builder> {
let ib = isa::lookup_by_name("aarch64-unknown-unknown").map_err(BasicError::from)?;
Ok(ib)
}
}

#[cfg(not(any(feature = "cranelift_x86", feature = "cranelift_arm64")))]
pub mod platform {
use super::*;

pub const IS_SUPPORTED: bool = false;
pub const USES_HEAP_REG: bool = false;

pub fn make_isa_builder(_env: &StaticEnvironment) -> DashResult<isa::Builder> {
Err("Platform not supported yet!".into())
}
}

impl From<isa::LookupError> for BasicError {
fn from(err: isa::LookupError) -> BasicError {
BasicError::new(err.to_string())
Expand Down Expand Up @@ -156,7 +224,7 @@ fn make_shared_flags(
if enable_jump_tables { "true" } else { "false" },
)?;

if cfg!(feature = "cranelift_x86") && cfg!(target_pointer_width = "64") {
if platform::USES_HEAP_REG {
sb.enable("enable_pinned_reg")?;
sb.enable("use_pinned_reg_as_heap_base")?;
}
Expand All @@ -168,55 +236,14 @@ fn make_shared_flags(
Ok(settings::Flags::new(sb))
}

#[cfg(feature = "cranelift_x86")]
fn make_isa_specific(env: &StaticEnvironment) -> DashResult<isa::Builder> {
let mut ib = isa::lookup_by_name("x86_64-unknown-unknown").map_err(BasicError::from)?;

if !env.has_sse2 {
return Err("SSE2 is mandatory for Baldrdash!".into());
}

if env.has_sse3 {
ib.enable("has_sse3").map_err(BasicError::from)?;
}
if env.has_sse41 {
ib.enable("has_sse41").map_err(BasicError::from)?;
}
if env.has_sse42 {
ib.enable("has_sse42").map_err(BasicError::from)?;
}
if env.has_popcnt {
ib.enable("has_popcnt").map_err(BasicError::from)?;
}
if env.has_avx {
ib.enable("has_avx").map_err(BasicError::from)?;
}
if env.has_bmi1 {
ib.enable("has_bmi1").map_err(BasicError::from)?;
}
if env.has_bmi2 {
ib.enable("has_bmi2").map_err(BasicError::from)?;
}
if env.has_lzcnt {
ib.enable("has_lzcnt").map_err(BasicError::from)?;
}

Ok(ib)
}

#[cfg(not(feature = "cranelift_x86"))]
fn make_isa_specific(_env: &StaticEnvironment) -> DashResult<isa::Builder> {
Err("Platform not supported yet!".into())
}

/// Allocate a `TargetISA` object that can be used to generate code for the CPU we're running on.
pub fn make_isa(env: &StaticEnvironment) -> DashResult<Box<dyn isa::TargetIsa>> {
// Parse flags defined by the environment variable.
let env_flags_str = std::env::var("CRANELIFT_FLAGS");
let env_flags = EnvVariableFlags::parse(&env_flags_str);

// Start with the ISA-independent settings.
let shared_flags = make_shared_flags(env, &env_flags).map_err(BasicError::from)?;
let ib = make_isa_specific(env)?;

let ib = platform::make_isa_builder(env)?;
Ok(ib.finish(shared_flags))
}
6 changes: 6 additions & 0 deletions js/src/wasm/cranelift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,9 @@ pub unsafe extern "C" fn cranelift_compile_function(

true
}

/// Returns true whether a platform (target ISA) is supported or not.
#[no_mangle]
pub unsafe extern "C" fn cranelift_supports_platform() -> bool {
isa::platform::IS_SUPPORTED
}
4 changes: 2 additions & 2 deletions js/src/wasm/cranelift/src/wasm2clif.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use cranelift_wasm::{

use crate::bindings::{self, GlobalDesc, SymbolicAddress};
use crate::compile::{symbolic_function_name, wasm_function_name};
use crate::isa::POINTER_SIZE;
use crate::isa::{platform::USES_HEAP_REG, POINTER_SIZE};

#[cfg(target_pointer_width = "64")]
pub const POINTER_TYPE: ir::Type = ir::types::I64;
Expand Down Expand Up @@ -544,7 +544,7 @@ impl<'static_env, 'module_env> TransEnv<'static_env, 'module_env> {
}

fn load_pinned_reg(&self, pos: &mut FuncCursor, vmctx: ir::Value) {
if cfg!(feature = "cranelift_x86") && cfg!(target_pointer_width = "64") {
if USES_HEAP_REG {
let heap_base = pos.ins().load(
POINTER_TYPE,
ir::MemFlags::trusted(),
Expand Down

0 comments on commit f0e5de2

Please sign in to comment.