Cranellift: remove Baldrdash support and related features. (#4571)
* Cranellift: remove Baldrdash support and related features.
As noted in Mozilla's bugzilla bug 1781425 [1], the SpiderMonkey team
has recently determined that their current form of integration with
Cranelift is too hard to maintain, and they have chosen to remove it
from their codebase. If and when they decide to build updated support
for Cranelift, they will adopt different approaches to several details
of the integration.
In the meantime, after discussion with the SpiderMonkey folks, they
agree that it makes sense to remove the bits of Cranelift that exist
to support the integration ("Baldrdash"), as they will not need
them. Many of these bits are difficult-to-maintain special cases that
are not actually tested in Cranelift proper: for example, the
Baldrdash integration required Cranelift to emit function bodies
without prologues/epilogues, and instead communicate very precise
information about the expected frame size and layout, then stitched
together something post-facto. This was brittle and caused a lot of
incidental complexity ("fallthrough returns", the resulting special
logic in block-ordering); this is just one example. As another
example, one particular Baldrdash ABI variant processed stack args in
reverse order, so our ABI code had to support both traversal
orders. We had a number of other Baldrdash-specific settings as well
that did various special things.
This PR removes Baldrdash ABI support, the `fallthrough_return`
instruction, and pulls some threads to remove now-unused bits as a
result of those two, with the understanding that the SpiderMonkey folks
will build new functionality as needed in the future and we can perhaps
find cleaner abstractions to make it all work.
[1] https://bugzilla.mozilla.org/show_bug.cgi?id=1781425
* Review feedback.
* Fix (?) DWARF debug tests: add `--disable-cache` to wasmtime invocations.
The debugger tests invoke `wasmtime` from within each test case under
the control of a debugger (gdb or lldb). Some of these tests started to
inexplicably fail in CI with unrelated changes, and the failures were
only inconsistently reproducible locally. It seems to be cache related:
if we disable cached compilation on the nested `wasmtime` invocations,
the tests consistently pass.
* Review feedback.
This commit is contained in:
@@ -26,102 +26,11 @@ pub(crate) type AArch64ABICallee = ABICalleeImpl<AArch64MachineDeps>;
|
||||
/// Support for the AArch64 ABI from the caller side (at a callsite).
|
||||
pub(crate) type AArch64ABICaller = ABICallerImpl<AArch64MachineDeps>;
|
||||
|
||||
// Spidermonkey specific ABI convention.
|
||||
|
||||
/// This is SpiderMonkey's `WasmTableCallSigReg`.
|
||||
static BALDRDASH_SIG_REG: u8 = 10;
|
||||
|
||||
/// This is SpiderMonkey's `WasmTlsReg`.
|
||||
static BALDRDASH_TLS_REG: u8 = 23;
|
||||
|
||||
/// Offset in stack-arg area to callee-TLS slot in Baldrdash-2020 calling convention.
|
||||
static BALDRDASH_CALLEE_TLS_OFFSET: i64 = 0;
|
||||
/// Offset in stack-arg area to caller-TLS slot in Baldrdash-2020 calling convention.
|
||||
static BALDRDASH_CALLER_TLS_OFFSET: i64 = 8;
|
||||
|
||||
// These two lists represent the registers the JIT may *not* use at any point in generated code.
|
||||
//
|
||||
// So these are callee-preserved from the JIT's point of view, and every register not in this list
|
||||
// has to be caller-preserved by definition.
|
||||
//
|
||||
// Keep these lists in sync with the NonAllocatableMask set in Spidermonkey's
|
||||
// Architecture-arm64.cpp.
|
||||
|
||||
// Indexed by physical register number.
|
||||
#[rustfmt::skip]
|
||||
static BALDRDASH_JIT_CALLEE_SAVED_GPR: &[bool] = &[
|
||||
/* 0 = */ false, false, false, false, false, false, false, false,
|
||||
/* 8 = */ false, false, false, false, false, false, false, false,
|
||||
/* 16 = */ true /* x16 / ip1 */, true /* x17 / ip2 */, true /* x18 / TLS */, false,
|
||||
/* 20 = */ false, false, false, false,
|
||||
/* 24 = */ false, false, false, false,
|
||||
// There should be 28, the pseudo stack pointer in this list, however the wasm stubs trash it
|
||||
// gladly right now.
|
||||
/* 28 = */ false, false, true /* x30 = FP */, false /* x31 = SP */
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
static BALDRDASH_JIT_CALLEE_SAVED_FPU: &[bool] = &[
|
||||
/* 0 = */ false, false, false, false, false, false, false, false,
|
||||
/* 8 = */ false, false, false, false, false, false, false, false,
|
||||
/* 16 = */ false, false, false, false, false, false, false, false,
|
||||
/* 24 = */ false, false, false, false, false, false, false, true /* v31 / d31 */
|
||||
];
|
||||
|
||||
/// This is the limit for the size of argument and return-value areas on the
|
||||
/// stack. We place a reasonable limit here to avoid integer overflow issues
|
||||
/// with 32-bit arithmetic: for now, 128 MB.
|
||||
static STACK_ARG_RET_SIZE_LIMIT: u64 = 128 * 1024 * 1024;
|
||||
|
||||
/// Try to fill a Baldrdash register, returning it if it was found.
|
||||
fn try_fill_baldrdash_reg(call_conv: isa::CallConv, param: &ir::AbiParam) -> Option<ABIArg> {
|
||||
if call_conv.extends_baldrdash() {
|
||||
match ¶m.purpose {
|
||||
&ir::ArgumentPurpose::VMContext => {
|
||||
// This is SpiderMonkey's `WasmTlsReg`.
|
||||
Some(ABIArg::reg(
|
||||
xreg(BALDRDASH_TLS_REG).to_real_reg().unwrap(),
|
||||
ir::types::I64,
|
||||
param.extension,
|
||||
param.purpose,
|
||||
))
|
||||
}
|
||||
&ir::ArgumentPurpose::SignatureId => {
|
||||
// This is SpiderMonkey's `WasmTableCallSigReg`.
|
||||
Some(ABIArg::reg(
|
||||
xreg(BALDRDASH_SIG_REG).to_real_reg().unwrap(),
|
||||
ir::types::I64,
|
||||
param.extension,
|
||||
param.purpose,
|
||||
))
|
||||
}
|
||||
&ir::ArgumentPurpose::CalleeTLS => {
|
||||
// This is SpiderMonkey's callee TLS slot in the extended frame of Wasm's ABI-2020.
|
||||
assert!(call_conv == isa::CallConv::Baldrdash2020);
|
||||
Some(ABIArg::stack(
|
||||
BALDRDASH_CALLEE_TLS_OFFSET,
|
||||
ir::types::I64,
|
||||
ir::ArgumentExtension::None,
|
||||
param.purpose,
|
||||
))
|
||||
}
|
||||
&ir::ArgumentPurpose::CallerTLS => {
|
||||
// This is SpiderMonkey's caller TLS slot in the extended frame of Wasm's ABI-2020.
|
||||
assert!(call_conv == isa::CallConv::Baldrdash2020);
|
||||
Some(ABIArg::stack(
|
||||
BALDRDASH_CALLER_TLS_OFFSET,
|
||||
ir::types::I64,
|
||||
ir::ArgumentExtension::None,
|
||||
param.purpose,
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<AMode> for StackAMode {
|
||||
fn into(self) -> AMode {
|
||||
match self {
|
||||
@@ -135,26 +44,19 @@ impl Into<AMode> for StackAMode {
|
||||
// Returns the size of stack space needed to store the
|
||||
// `int_reg` and `vec_reg`.
|
||||
fn saved_reg_stack_size(
|
||||
call_conv: isa::CallConv,
|
||||
int_reg: &[Writable<RealReg>],
|
||||
vec_reg: &[Writable<RealReg>],
|
||||
) -> (usize, usize) {
|
||||
// Round up to multiple of 2, to keep 16-byte stack alignment.
|
||||
let int_save_bytes = (int_reg.len() + (int_reg.len() & 1)) * 8;
|
||||
// The Baldrdash ABIs require saving and restoring the whole 16-byte
|
||||
// SIMD & FP registers, so the necessary stack space is always a
|
||||
// multiple of the mandatory 16-byte stack alignment. However, the
|
||||
// Procedure Call Standard for the Arm 64-bit Architecture (AAPCS64,
|
||||
// including several related ABIs such as the one used by Windows)
|
||||
// mandates saving only the bottom 8 bytes of the vector registers,
|
||||
// so in that case we round up the number of registers to ensure proper
|
||||
// stack alignment (similarly to the situation with `int_reg`).
|
||||
let vec_reg_size = if call_conv.extends_baldrdash() { 16 } else { 8 };
|
||||
let vec_save_padding = if call_conv.extends_baldrdash() {
|
||||
0
|
||||
} else {
|
||||
vec_reg.len() & 1
|
||||
};
|
||||
// The Procedure Call Standard for the Arm 64-bit Architecture
|
||||
// (AAPCS64, including several related ABIs such as the one used by
|
||||
// Windows) mandates saving only the bottom 8 bytes of the vector
|
||||
// registers, so we round up the number of registers to ensure
|
||||
// proper stack alignment (similarly to the situation with
|
||||
// `int_reg`).
|
||||
let vec_reg_size = 8;
|
||||
let vec_save_padding = vec_reg.len() & 1;
|
||||
// FIXME: SVE: ABI is different to Neon, so do we treat all vec regs as Z-regs?
|
||||
let vec_save_bytes = (vec_reg.len() + vec_save_padding) * vec_reg_size;
|
||||
|
||||
@@ -185,8 +87,6 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
add_ret_area_ptr: bool,
|
||||
) -> CodegenResult<(Vec<ABIArg>, i64, Option<usize>)> {
|
||||
let is_apple_cc = call_conv.extends_apple_aarch64();
|
||||
let is_baldrdash = call_conv.extends_baldrdash();
|
||||
let has_baldrdash_tls = call_conv == isa::CallConv::Baldrdash2020;
|
||||
|
||||
// See AArch64 ABI (https://github.com/ARM-software/abi-aa/blob/2021Q1/aapcs64/aapcs64.rst#64parameter-passing), sections 6.4.
|
||||
//
|
||||
@@ -207,12 +107,6 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
let mut next_stack: u64 = 0;
|
||||
let mut ret = vec![];
|
||||
|
||||
if args_or_rets == ArgsOrRets::Args && has_baldrdash_tls {
|
||||
// Baldrdash ABI-2020 always has two stack-arg slots reserved, for the callee and
|
||||
// caller TLS-register values, respectively.
|
||||
next_stack = 16;
|
||||
}
|
||||
|
||||
let (max_per_class_reg_vals, mut remaining_reg_vals) = match args_or_rets {
|
||||
ArgsOrRets::Args => (8, 16), // x0-x7 and v0-v7
|
||||
|
||||
@@ -222,12 +116,12 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
// we can return values in up to 8 integer and
|
||||
// 8 vector registers at once.
|
||||
//
|
||||
// In Baldrdash and Wasmtime, we can only use one register for
|
||||
// return value for all the register classes. That is, we can't
|
||||
// return values in both one integer and one vector register; only
|
||||
// one return value may be in a register.
|
||||
// In Wasmtime, we can only use one register for return
|
||||
// value for all the register classes. That is, we can't
|
||||
// return values in both one integer and one vector
|
||||
// register; only one return value may be in a register.
|
||||
ArgsOrRets::Rets => {
|
||||
if is_baldrdash || call_conv.extends_wasmtime() {
|
||||
if call_conv.extends_wasmtime() {
|
||||
(1, 1) // x0 or v0, but not both
|
||||
} else {
|
||||
(8, 16) // x0-x7 and v0-v7
|
||||
@@ -235,23 +129,13 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
}
|
||||
};
|
||||
|
||||
for i in 0..params.len() {
|
||||
// Process returns backward, according to the SpiderMonkey ABI (which we
|
||||
// adopt internally if `is_baldrdash` is set).
|
||||
let param = match (args_or_rets, is_baldrdash) {
|
||||
(ArgsOrRets::Args, _) => ¶ms[i],
|
||||
(ArgsOrRets::Rets, false) => ¶ms[i],
|
||||
(ArgsOrRets::Rets, true) => ¶ms[params.len() - 1 - i],
|
||||
};
|
||||
|
||||
for param in params {
|
||||
// Validate "purpose".
|
||||
match ¶m.purpose {
|
||||
&ir::ArgumentPurpose::VMContext
|
||||
| &ir::ArgumentPurpose::Normal
|
||||
| &ir::ArgumentPurpose::StackLimit
|
||||
| &ir::ArgumentPurpose::SignatureId
|
||||
| &ir::ArgumentPurpose::CallerTLS
|
||||
| &ir::ArgumentPurpose::CalleeTLS
|
||||
| &ir::ArgumentPurpose::StructReturn
|
||||
| &ir::ArgumentPurpose::StructArgument(_) => {}
|
||||
_ => panic!(
|
||||
@@ -268,12 +152,6 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
|
||||
let (rcs, reg_types) = Inst::rc_for_type(param.value_type)?;
|
||||
|
||||
if let Some(param) = try_fill_baldrdash_reg(call_conv, param) {
|
||||
assert!(rcs[0] == RegClass::Int);
|
||||
ret.push(param);
|
||||
continue;
|
||||
}
|
||||
|
||||
if let ir::ArgumentPurpose::StructArgument(size) = param.purpose {
|
||||
let offset = next_stack as i64;
|
||||
let size = size as u64;
|
||||
@@ -432,10 +310,6 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
next_stack += size;
|
||||
}
|
||||
|
||||
if args_or_rets == ArgsOrRets::Rets && is_baldrdash {
|
||||
ret.reverse();
|
||||
}
|
||||
|
||||
let extra_arg = if add_ret_area_ptr {
|
||||
debug_assert!(args_or_rets == ArgsOrRets::Args);
|
||||
if next_xreg < max_per_class_reg_vals && remaining_reg_vals > 0 {
|
||||
@@ -470,15 +344,8 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
Ok((ret, next_stack as i64, extra_arg))
|
||||
}
|
||||
|
||||
fn fp_to_arg_offset(call_conv: isa::CallConv, flags: &settings::Flags) -> i64 {
|
||||
if call_conv.extends_baldrdash() {
|
||||
let num_words = flags.baldrdash_prologue_words() as i64;
|
||||
debug_assert!(num_words > 0, "baldrdash must set baldrdash_prologue_words");
|
||||
debug_assert_eq!(num_words % 2, 0, "stack must be 16-aligned");
|
||||
num_words * 8
|
||||
} else {
|
||||
16 // frame pointer + return address.
|
||||
}
|
||||
fn fp_to_arg_offset(_call_conv: isa::CallConv, _flags: &settings::Flags) -> i64 {
|
||||
16 // frame pointer + return address.
|
||||
}
|
||||
|
||||
fn gen_load_stack(mem: StackAMode, into_reg: Writable<Reg>, ty: Type) -> Inst {
|
||||
@@ -560,10 +427,6 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
insts
|
||||
}
|
||||
|
||||
fn gen_epilogue_placeholder() -> Inst {
|
||||
Inst::EpiloguePlaceholder
|
||||
}
|
||||
|
||||
fn gen_get_stack_addr(mem: StackAMode, into_reg: Writable<Reg>, _ty: Type) -> Inst {
|
||||
// FIXME: Do something different for dynamic types?
|
||||
let mem = mem.into();
|
||||
@@ -712,7 +575,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
// Returns stack bytes used as well as instructions. Does not adjust
|
||||
// nominal SP offset; abi_impl generic code will do that.
|
||||
fn gen_clobber_save(
|
||||
call_conv: isa::CallConv,
|
||||
_call_conv: isa::CallConv,
|
||||
setup_frame: bool,
|
||||
flags: &settings::Flags,
|
||||
clobbered_callee_saves: &[Writable<RealReg>],
|
||||
@@ -729,8 +592,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
}
|
||||
}
|
||||
|
||||
let (int_save_bytes, vec_save_bytes) =
|
||||
saved_reg_stack_size(call_conv, &clobbered_int, &clobbered_vec);
|
||||
let (int_save_bytes, vec_save_bytes) = saved_reg_stack_size(&clobbered_int, &clobbered_vec);
|
||||
let total_save_bytes = int_save_bytes + vec_save_bytes;
|
||||
let clobber_size = total_save_bytes as i32;
|
||||
let mut insts = SmallVec::new();
|
||||
@@ -826,26 +688,13 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
}
|
||||
}
|
||||
|
||||
let store_vec_reg = |rd| {
|
||||
if call_conv.extends_baldrdash() {
|
||||
Inst::FpuStore128 {
|
||||
rd,
|
||||
mem: AMode::PreIndexed(
|
||||
writable_stack_reg(),
|
||||
SImm9::maybe_from_i64(-clobber_offset_change).unwrap(),
|
||||
),
|
||||
flags: MemFlags::trusted(),
|
||||
}
|
||||
} else {
|
||||
Inst::FpuStore64 {
|
||||
rd,
|
||||
mem: AMode::PreIndexed(
|
||||
writable_stack_reg(),
|
||||
SImm9::maybe_from_i64(-clobber_offset_change).unwrap(),
|
||||
),
|
||||
flags: MemFlags::trusted(),
|
||||
}
|
||||
}
|
||||
let store_vec_reg = |rd| Inst::FpuStore64 {
|
||||
rd,
|
||||
mem: AMode::PreIndexed(
|
||||
writable_stack_reg(),
|
||||
SImm9::maybe_from_i64(-clobber_offset_change).unwrap(),
|
||||
),
|
||||
flags: MemFlags::trusted(),
|
||||
};
|
||||
let iter = clobbered_vec.chunks_exact(2);
|
||||
|
||||
@@ -867,37 +716,20 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
}
|
||||
|
||||
let store_vec_reg_pair = |rt, rt2| {
|
||||
if call_conv.extends_baldrdash() {
|
||||
let clobber_offset_change = 32;
|
||||
let clobber_offset_change = 16;
|
||||
|
||||
(
|
||||
Inst::FpuStoreP128 {
|
||||
rt,
|
||||
rt2,
|
||||
mem: PairAMode::PreIndexed(
|
||||
writable_stack_reg(),
|
||||
SImm7Scaled::maybe_from_i64(-clobber_offset_change, I8X16).unwrap(),
|
||||
),
|
||||
flags: MemFlags::trusted(),
|
||||
},
|
||||
clobber_offset_change as u32,
|
||||
)
|
||||
} else {
|
||||
let clobber_offset_change = 16;
|
||||
|
||||
(
|
||||
Inst::FpuStoreP64 {
|
||||
rt,
|
||||
rt2,
|
||||
mem: PairAMode::PreIndexed(
|
||||
writable_stack_reg(),
|
||||
SImm7Scaled::maybe_from_i64(-clobber_offset_change, F64).unwrap(),
|
||||
),
|
||||
flags: MemFlags::trusted(),
|
||||
},
|
||||
clobber_offset_change as u32,
|
||||
)
|
||||
}
|
||||
(
|
||||
Inst::FpuStoreP64 {
|
||||
rt,
|
||||
rt2,
|
||||
mem: PairAMode::PreIndexed(
|
||||
writable_stack_reg(),
|
||||
SImm7Scaled::maybe_from_i64(-clobber_offset_change, F64).unwrap(),
|
||||
),
|
||||
flags: MemFlags::trusted(),
|
||||
},
|
||||
clobber_offset_change as u32,
|
||||
)
|
||||
};
|
||||
let mut iter = iter.rev();
|
||||
|
||||
@@ -938,7 +770,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
}
|
||||
|
||||
fn gen_clobber_restore(
|
||||
call_conv: isa::CallConv,
|
||||
_call_conv: isa::CallConv,
|
||||
sig: &Signature,
|
||||
flags: &settings::Flags,
|
||||
clobbers: &[Writable<RealReg>],
|
||||
@@ -946,57 +778,26 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
_outgoing_args_size: u32,
|
||||
) -> SmallVec<[Inst; 16]> {
|
||||
let mut insts = SmallVec::new();
|
||||
let (clobbered_int, clobbered_vec) =
|
||||
get_regs_restored_in_epilogue(call_conv, flags, sig, clobbers);
|
||||
let (clobbered_int, clobbered_vec) = get_regs_restored_in_epilogue(flags, sig, clobbers);
|
||||
|
||||
// Free the fixed frame if necessary.
|
||||
if fixed_frame_storage_size > 0 {
|
||||
insts.extend(Self::gen_sp_reg_adjust(fixed_frame_storage_size as i32));
|
||||
}
|
||||
|
||||
let load_vec_reg = |rd| {
|
||||
if call_conv.extends_baldrdash() {
|
||||
Inst::FpuLoad128 {
|
||||
rd,
|
||||
mem: AMode::PostIndexed(
|
||||
writable_stack_reg(),
|
||||
SImm9::maybe_from_i64(16).unwrap(),
|
||||
),
|
||||
flags: MemFlags::trusted(),
|
||||
}
|
||||
} else {
|
||||
Inst::FpuLoad64 {
|
||||
rd,
|
||||
mem: AMode::PostIndexed(
|
||||
writable_stack_reg(),
|
||||
SImm9::maybe_from_i64(16).unwrap(),
|
||||
),
|
||||
flags: MemFlags::trusted(),
|
||||
}
|
||||
}
|
||||
let load_vec_reg = |rd| Inst::FpuLoad64 {
|
||||
rd,
|
||||
mem: AMode::PostIndexed(writable_stack_reg(), SImm9::maybe_from_i64(16).unwrap()),
|
||||
flags: MemFlags::trusted(),
|
||||
};
|
||||
let load_vec_reg_pair = |rt, rt2| {
|
||||
if call_conv.extends_baldrdash() {
|
||||
Inst::FpuLoadP128 {
|
||||
rt,
|
||||
rt2,
|
||||
mem: PairAMode::PostIndexed(
|
||||
writable_stack_reg(),
|
||||
SImm7Scaled::maybe_from_i64(32, I8X16).unwrap(),
|
||||
),
|
||||
flags: MemFlags::trusted(),
|
||||
}
|
||||
} else {
|
||||
Inst::FpuLoadP64 {
|
||||
rt,
|
||||
rt2,
|
||||
mem: PairAMode::PostIndexed(
|
||||
writable_stack_reg(),
|
||||
SImm7Scaled::maybe_from_i64(16, F64).unwrap(),
|
||||
),
|
||||
flags: MemFlags::trusted(),
|
||||
}
|
||||
}
|
||||
let load_vec_reg_pair = |rt, rt2| Inst::FpuLoadP64 {
|
||||
rt,
|
||||
rt2,
|
||||
mem: PairAMode::PostIndexed(
|
||||
writable_stack_reg(),
|
||||
SImm7Scaled::maybe_from_i64(16, F64).unwrap(),
|
||||
),
|
||||
flags: MemFlags::trusted(),
|
||||
};
|
||||
|
||||
let mut iter = clobbered_vec.chunks_exact(2);
|
||||
@@ -1053,19 +854,6 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
});
|
||||
}
|
||||
|
||||
// If this is Baldrdash-2020, restore the callee (i.e., our) TLS
|
||||
// register. We may have allocated it for something else and clobbered
|
||||
// it, but the ABI expects us to leave the TLS register unchanged.
|
||||
if call_conv == isa::CallConv::Baldrdash2020 {
|
||||
let off = BALDRDASH_CALLEE_TLS_OFFSET + Self::fp_to_arg_offset(call_conv, flags);
|
||||
insts.push(Inst::gen_load(
|
||||
writable_xreg(BALDRDASH_TLS_REG),
|
||||
AMode::UnsignedOffset(fp_reg(), UImm12Scaled::maybe_from_i64(off, I64).unwrap()),
|
||||
I64,
|
||||
MemFlags::trusted(),
|
||||
));
|
||||
}
|
||||
|
||||
insts
|
||||
}
|
||||
|
||||
@@ -1132,8 +920,6 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
src: Reg,
|
||||
size: usize,
|
||||
) -> SmallVec<[Self::I; 8]> {
|
||||
// Baldrdash should not use struct args.
|
||||
assert!(!call_conv.extends_baldrdash());
|
||||
let mut insts = SmallVec::new();
|
||||
let arg0 = writable_xreg(0);
|
||||
let arg1 = writable_xreg(1);
|
||||
@@ -1174,36 +960,19 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
s.nominal_sp_to_fp
|
||||
}
|
||||
|
||||
fn get_regs_clobbered_by_call(call_conv_of_callee: isa::CallConv) -> PRegSet {
|
||||
let mut clobbers = DEFAULT_AAPCS_CLOBBERS;
|
||||
|
||||
if call_conv_of_callee.extends_baldrdash() {
|
||||
// Every X-register except for x16, x17, x18 is
|
||||
// caller-saved (clobbered by a call).
|
||||
for i in 19..=28 {
|
||||
clobbers.add(xreg_preg(i));
|
||||
}
|
||||
clobbers.add(vreg_preg(31));
|
||||
}
|
||||
|
||||
clobbers
|
||||
fn get_regs_clobbered_by_call(_call_conv_of_callee: isa::CallConv) -> PRegSet {
|
||||
DEFAULT_AAPCS_CLOBBERS
|
||||
}
|
||||
|
||||
fn get_ext_mode(
|
||||
call_conv: isa::CallConv,
|
||||
specified: ir::ArgumentExtension,
|
||||
_call_conv: isa::CallConv,
|
||||
_specified: ir::ArgumentExtension,
|
||||
) -> ir::ArgumentExtension {
|
||||
if call_conv.extends_baldrdash() {
|
||||
// Baldrdash (SpiderMonkey) always extends args and return values to the full register.
|
||||
specified
|
||||
} else {
|
||||
// No other supported ABI on AArch64 does so.
|
||||
ir::ArgumentExtension::None
|
||||
}
|
||||
ir::ArgumentExtension::None
|
||||
}
|
||||
|
||||
fn get_clobbered_callee_saves(
|
||||
call_conv: isa::CallConv,
|
||||
_call_conv: isa::CallConv,
|
||||
flags: &settings::Flags,
|
||||
sig: &Signature,
|
||||
regs: &[Writable<RealReg>],
|
||||
@@ -1211,9 +980,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
||||
let mut regs: Vec<Writable<RealReg>> = regs
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|r| {
|
||||
is_reg_saved_in_prologue(call_conv, flags.enable_pinned_reg(), sig, r.to_reg())
|
||||
})
|
||||
.filter(|r| is_reg_saved_in_prologue(flags.enable_pinned_reg(), sig, r.to_reg()))
|
||||
.collect();
|
||||
|
||||
// Sort registers for deterministic code output. We can do an unstable
|
||||
@@ -1248,25 +1015,7 @@ fn legal_type_for_machine(ty: Type) -> bool {
|
||||
|
||||
/// Is the given register saved in the prologue if clobbered, i.e., is it a
|
||||
/// callee-save?
|
||||
fn is_reg_saved_in_prologue(
|
||||
call_conv: isa::CallConv,
|
||||
enable_pinned_reg: bool,
|
||||
sig: &Signature,
|
||||
r: RealReg,
|
||||
) -> bool {
|
||||
if call_conv.extends_baldrdash() {
|
||||
match r.class() {
|
||||
RegClass::Int => {
|
||||
let enc = r.hw_enc() & 31;
|
||||
return BALDRDASH_JIT_CALLEE_SAVED_GPR[enc as usize];
|
||||
}
|
||||
RegClass::Float => {
|
||||
let enc = r.hw_enc() & 31;
|
||||
return BALDRDASH_JIT_CALLEE_SAVED_FPU[enc as usize];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn is_reg_saved_in_prologue(enable_pinned_reg: bool, sig: &Signature, r: RealReg) -> bool {
|
||||
// FIXME: We need to inspect whether a function is returning Z or P regs too.
|
||||
let save_z_regs = sig
|
||||
.params
|
||||
@@ -1307,7 +1056,6 @@ fn is_reg_saved_in_prologue(
|
||||
/// prologue and restored in the epilogue, given the set of all registers
|
||||
/// written by the function's body.
|
||||
fn get_regs_restored_in_epilogue(
|
||||
call_conv: isa::CallConv,
|
||||
flags: &settings::Flags,
|
||||
sig: &Signature,
|
||||
regs: &[Writable<RealReg>],
|
||||
@@ -1315,7 +1063,7 @@ fn get_regs_restored_in_epilogue(
|
||||
let mut int_saves = vec![];
|
||||
let mut vec_saves = vec![];
|
||||
for ® in regs {
|
||||
if is_reg_saved_in_prologue(call_conv, flags.enable_pinned_reg(), sig, reg.to_reg()) {
|
||||
if is_reg_saved_in_prologue(flags.enable_pinned_reg(), sig, reg.to_reg()) {
|
||||
match reg.to_reg().class() {
|
||||
RegClass::Int => int_saves.push(reg),
|
||||
RegClass::Float => vec_saves.push(reg),
|
||||
|
||||
@@ -666,10 +666,6 @@
|
||||
(Ret
|
||||
(rets VecReg))
|
||||
|
||||
;; A placeholder instruction, generating no code, meaning that a function epilogue must be
|
||||
;; inserted there.
|
||||
(EpiloguePlaceholder)
|
||||
|
||||
;; An unconditional branch.
|
||||
(Jump
|
||||
(dest BranchTarget))
|
||||
@@ -707,7 +703,6 @@
|
||||
;; An instruction guaranteed to always be undefined and to trigger an illegal instruction at
|
||||
;; runtime.
|
||||
(Udf
|
||||
(use_allocated_encoding bool)
|
||||
(trap_code TrapCode))
|
||||
|
||||
;; Compute the address (using a PC-relative offset) of a memory location, using the `ADR`
|
||||
@@ -2107,9 +2102,9 @@
|
||||
|
||||
;; Helper for generating a `udf` instruction.
|
||||
|
||||
(decl udf (bool TrapCode) SideEffectNoResult)
|
||||
(rule (udf use_allocated_encoding trap_code)
|
||||
(SideEffectNoResult.Inst (MInst.Udf use_allocated_encoding trap_code)))
|
||||
(decl udf (TrapCode) SideEffectNoResult)
|
||||
(rule (udf trap_code)
|
||||
(SideEffectNoResult.Inst (MInst.Udf trap_code)))
|
||||
|
||||
;; Immediate value helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
@@ -618,8 +618,6 @@ pub struct EmitState {
|
||||
stack_map: Option<StackMap>,
|
||||
/// Current source-code location corresponding to instruction to be emitted.
|
||||
cur_srcloc: SourceLoc,
|
||||
/// Is code generated for the SpiderMonkey WebAssembly convention.
|
||||
is_baldrdash_target: bool,
|
||||
}
|
||||
|
||||
impl MachInstEmitState<Inst> for EmitState {
|
||||
@@ -629,7 +627,6 @@ impl MachInstEmitState<Inst> for EmitState {
|
||||
nominal_sp_to_fp: abi.frame_size() as i64,
|
||||
stack_map: None,
|
||||
cur_srcloc: SourceLoc::default(),
|
||||
is_baldrdash_target: abi.call_conv().extends_baldrdash(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2768,9 +2765,6 @@ impl MachInstEmit for Inst {
|
||||
&Inst::Ret { .. } => {
|
||||
sink.put4(0xd65f03c0);
|
||||
}
|
||||
&Inst::EpiloguePlaceholder => {
|
||||
// Noop; this is just a placeholder for epilogues.
|
||||
}
|
||||
&Inst::Call { ref info } => {
|
||||
if let Some(s) = state.take_stack_map() {
|
||||
sink.add_stack_map(StackMapExtent::UpcomingBytes(4), s);
|
||||
@@ -2826,10 +2820,7 @@ impl MachInstEmit for Inst {
|
||||
));
|
||||
sink.use_label_at_offset(off, label, LabelUse::Branch19);
|
||||
// udf
|
||||
let trap = Inst::Udf {
|
||||
use_allocated_encoding: !state.is_baldrdash_target,
|
||||
trap_code,
|
||||
};
|
||||
let trap = Inst::Udf { trap_code };
|
||||
trap.emit(&[], sink, emit_info, state);
|
||||
// LABEL:
|
||||
sink.bind_label(label);
|
||||
@@ -2845,15 +2836,10 @@ impl MachInstEmit for Inst {
|
||||
&Inst::Brk => {
|
||||
sink.put4(0xd4200000);
|
||||
}
|
||||
&Inst::Udf {
|
||||
use_allocated_encoding,
|
||||
trap_code,
|
||||
} => {
|
||||
let encoding = if use_allocated_encoding {
|
||||
0xc11f
|
||||
} else {
|
||||
0xd4a00000
|
||||
};
|
||||
&Inst::Udf { trap_code } => {
|
||||
// "CLIF" in hex, to make the trap recognizable during
|
||||
// debugging.
|
||||
let encoding = 0xc11f;
|
||||
|
||||
sink.add_trap(trap_code);
|
||||
if let Some(s) = state.take_stack_map() {
|
||||
@@ -2985,11 +2971,7 @@ impl MachInstEmit for Inst {
|
||||
};
|
||||
inst.emit(&[], sink, emit_info, state);
|
||||
sink.add_reloc(Reloc::Abs8, name, offset);
|
||||
if emit_info.0.emit_all_ones_funcaddrs() {
|
||||
sink.put8(u64::max_value());
|
||||
} else {
|
||||
sink.put8(0);
|
||||
}
|
||||
sink.put8(0);
|
||||
}
|
||||
&Inst::LoadAddr { rd, ref mem } => {
|
||||
let rd = allocs.next_writable(rd);
|
||||
|
||||
@@ -43,11 +43,10 @@ fn test_aarch64_binemit() {
|
||||
insns.push((Inst::Csdb, "9F2203D5", "csdb"));
|
||||
insns.push((
|
||||
Inst::Udf {
|
||||
use_allocated_encoding: false,
|
||||
trap_code: TrapCode::Interrupt,
|
||||
},
|
||||
"0000A0D4",
|
||||
"udf",
|
||||
"1FC10000",
|
||||
"udf #0xc11f",
|
||||
));
|
||||
insns.push((
|
||||
Inst::AluRRR {
|
||||
|
||||
@@ -975,7 +975,7 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
|
||||
collector.reg_use(ret);
|
||||
}
|
||||
}
|
||||
&Inst::Jump { .. } | &Inst::EpiloguePlaceholder => {}
|
||||
&Inst::Jump { .. } => {}
|
||||
&Inst::Call { ref info, .. } => {
|
||||
collector.reg_uses(&info.uses[..]);
|
||||
collector.reg_defs(&info.defs[..]);
|
||||
@@ -1062,14 +1062,6 @@ impl MachInst for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_epilogue_placeholder(&self) -> bool {
|
||||
if let Inst::EpiloguePlaceholder = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_included_in_clobbers(&self) -> bool {
|
||||
// We exclude call instructions from the clobber-set when they are calls
|
||||
// from caller to callee with the same ABI. Such calls cannot possibly
|
||||
@@ -1090,7 +1082,7 @@ impl MachInst for Inst {
|
||||
|
||||
fn is_term(&self) -> MachTerminator {
|
||||
match self {
|
||||
&Inst::Ret { .. } | &Inst::EpiloguePlaceholder => MachTerminator::Ret,
|
||||
&Inst::Ret { .. } => MachTerminator::Ret,
|
||||
&Inst::Jump { .. } => MachTerminator::Uncond,
|
||||
&Inst::CondBr { .. } => MachTerminator::Cond,
|
||||
&Inst::IndirectBr { .. } => MachTerminator::Indirect,
|
||||
@@ -2472,7 +2464,6 @@ impl Inst {
|
||||
format!("blr {}", rn)
|
||||
}
|
||||
&Inst::Ret { .. } => "ret".to_string(),
|
||||
&Inst::EpiloguePlaceholder => "epilogue placeholder".to_string(),
|
||||
&Inst::Jump { ref dest } => {
|
||||
let dest = dest.pretty_print(0, allocs);
|
||||
format!("b {}", dest)
|
||||
@@ -2504,16 +2495,7 @@ impl Inst {
|
||||
format!("br {}", rn)
|
||||
}
|
||||
&Inst::Brk => "brk #0".to_string(),
|
||||
&Inst::Udf {
|
||||
use_allocated_encoding,
|
||||
..
|
||||
} => {
|
||||
if use_allocated_encoding {
|
||||
"udf #0xc11f".to_string()
|
||||
} else {
|
||||
"udf".to_string()
|
||||
}
|
||||
}
|
||||
&Inst::Udf { .. } => "udf #0xc11f".to_string(),
|
||||
&Inst::TrapIf { ref kind, .. } => match kind {
|
||||
&CondBrKind::Zero(reg) => {
|
||||
let reg = pretty_print_reg(reg, allocs);
|
||||
|
||||
@@ -1524,14 +1524,12 @@
|
||||
;;;; Rules for `trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule (lower (trap trap_code))
|
||||
(let ((use_allocated_encoding bool (is_not_baldrdash_call_conv)))
|
||||
(side_effect (udf use_allocated_encoding trap_code))))
|
||||
(side_effect (udf trap_code)))
|
||||
|
||||
;;;; Rules for `resumable_trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule (lower (resumable_trap trap_code))
|
||||
(let ((use_allocated_encoding bool (is_not_baldrdash_call_conv)))
|
||||
(side_effect (udf use_allocated_encoding trap_code))))
|
||||
(side_effect (udf trap_code)))
|
||||
|
||||
;;;; Rules for `splat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
@@ -463,7 +463,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
||||
}
|
||||
}
|
||||
|
||||
Opcode::FallthroughReturn | Opcode::Return => {
|
||||
Opcode::Return => {
|
||||
for (i, input) in inputs.iter().enumerate() {
|
||||
// N.B.: according to the AArch64 ABI, the top bits of a register
|
||||
// (above the bits for the value's type) are undefined, so we
|
||||
|
||||
Reference in New Issue
Block a user