Fix miscompilations and other nasty errors
This commit is contained in:
498
src/backend.rs
498
src/backend.rs
File diff suppressed because it is too large
Load Diff
@@ -151,22 +151,58 @@ where
|
|||||||
block.is_next = true;
|
block.is_next = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Operator::Label(_) = op {
|
macro_rules! assert_ge {
|
||||||
} else {
|
($left:expr, $right:expr) => ({
|
||||||
debug_assert_eq!(
|
match (&$left, &$right) {
|
||||||
{
|
(left_val, right_val) => {
|
||||||
|
if !(*left_val >= *right_val) {
|
||||||
|
// The reborrows below are intentional. Without them, the stack slot for the
|
||||||
|
// borrow is initialized even before the values are compared, leading to a
|
||||||
|
// noticeable slow down.
|
||||||
|
panic!(r#"assertion failed: `(left >= right)`
|
||||||
|
left: `{:?}`,
|
||||||
|
right: `{:?}`"#, &*left_val, &*right_val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
($left:expr, $right:expr,) => ({
|
||||||
|
assert_ge!($left, $right)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// `cfg` on blocks doesn't work in the compiler right now, so we have to write a dummy macro
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
macro_rules! assertions {
|
||||||
|
() => {
|
||||||
|
if let Operator::Label(label) = &op {
|
||||||
|
let block = &blocks[&BrTarget::Label(label.clone())];
|
||||||
|
let num_cc_params = block.calling_convention.as_ref().map(|cc| match cc {
|
||||||
|
Left(cc) => cc.arguments.len(),
|
||||||
|
Right(cc) => cc.stack.len(),
|
||||||
|
});
|
||||||
|
if let Some(num_cc_params) = num_cc_params {
|
||||||
|
assert_ge!(num_cc_params, block.params as usize);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
let mut actual_regs = Registers::new();
|
let mut actual_regs = Registers::new();
|
||||||
for val in &ctx.block_state.stack {
|
for val in &ctx.block_state.stack {
|
||||||
if let ValueLocation::Reg(gpr) = val {
|
if let ValueLocation::Reg(gpr) = val {
|
||||||
actual_regs.mark_used(*gpr);
|
actual_regs.mark_used(*gpr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
actual_regs
|
assert_eq!(actual_regs, ctx.block_state.regs,);
|
||||||
},
|
}
|
||||||
ctx.block_state.regs,
|
};
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
macro_rules! assertions {
|
||||||
|
() => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
assertions!();
|
||||||
|
|
||||||
struct DisassemblyOpFormatter<Label>(Operator<Label>);
|
struct DisassemblyOpFormatter<Label>(Operator<Label>);
|
||||||
|
|
||||||
impl<Label> fmt::Display for DisassemblyOpFormatter<Label>
|
impl<Label> fmt::Display for DisassemblyOpFormatter<Label>
|
||||||
@@ -348,14 +384,15 @@ where
|
|||||||
let f = |ctx: &mut Context<_>| {
|
let f = |ctx: &mut Context<_>| {
|
||||||
let then_block_should_serialize_args = then_block.should_serialize_args();
|
let then_block_should_serialize_args = then_block.should_serialize_args();
|
||||||
let else_block_should_serialize_args = else_block.should_serialize_args();
|
let else_block_should_serialize_args = else_block.should_serialize_args();
|
||||||
|
let max_params = then_block.params.max(else_block.params);
|
||||||
|
|
||||||
match (
|
match (
|
||||||
(&mut then_block.calling_convention, &then.to_drop),
|
(&mut then_block.calling_convention, &then.to_drop),
|
||||||
(&mut else_block.calling_convention, &else_.to_drop),
|
(&mut else_block.calling_convention, &else_.to_drop),
|
||||||
) {
|
) {
|
||||||
((Some(Left(ref cc)), to_drop), ref mut other @ (None, _))
|
((Some(Left(ref cc)), _), ref mut other @ (None, _))
|
||||||
| (ref mut other @ (None, _), (Some(Left(ref cc)), to_drop)) => {
|
| (ref mut other @ (None, _), (Some(Left(ref cc)), _)) => {
|
||||||
let mut cc = ctx.serialize_block_args(cc, to_drop.clone());
|
let mut cc = ctx.serialize_block_args(cc, max_params);
|
||||||
if let Some(to_drop) = other.1 {
|
if let Some(to_drop) = other.1 {
|
||||||
drop_elements(&mut cc.arguments, to_drop.clone());
|
drop_elements(&mut cc.arguments, to_drop.clone());
|
||||||
}
|
}
|
||||||
@@ -365,7 +402,6 @@ where
|
|||||||
(ref mut then_cc @ None, then_to_drop),
|
(ref mut then_cc @ None, then_to_drop),
|
||||||
(ref mut else_cc @ None, else_to_drop),
|
(ref mut else_cc @ None, else_to_drop),
|
||||||
) => {
|
) => {
|
||||||
let max_params = then_block.params.max(else_block.params);
|
|
||||||
let virt_cc = if !then_block_should_serialize_args
|
let virt_cc = if !then_block_should_serialize_args
|
||||||
|| !else_block_should_serialize_args
|
|| !else_block_should_serialize_args
|
||||||
{
|
{
|
||||||
@@ -436,7 +472,12 @@ where
|
|||||||
(
|
(
|
||||||
if def.is_next { None } else { Some(def.label) },
|
if def.is_next { None } else { Some(def.label) },
|
||||||
def.num_callers,
|
def.num_callers,
|
||||||
def.params,
|
def.params
|
||||||
|
+ default
|
||||||
|
.to_drop
|
||||||
|
.as_ref()
|
||||||
|
.map(|t| t.clone().count())
|
||||||
|
.unwrap_or_default() as u32,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -462,9 +503,7 @@ where
|
|||||||
block.actual_num_callers += 1;
|
block.actual_num_callers += 1;
|
||||||
|
|
||||||
if block.calling_convention.is_some() {
|
if block.calling_convention.is_some() {
|
||||||
let new_cc = block.calling_convention
|
let new_cc = block.calling_convention.clone();
|
||||||
.clone()
|
|
||||||
.map(|cc| (cc, target.to_drop.clone()));
|
|
||||||
assert!(cc.is_none() || cc == new_cc, "Can't pass different params to different elements of `br_table` yet");
|
assert!(cc.is_none() || cc == new_cc, "Can't pass different params to different elements of `br_table` yet");
|
||||||
cc = new_cc;
|
cc = new_cc;
|
||||||
}
|
}
|
||||||
@@ -473,12 +512,19 @@ where
|
|||||||
max_num_callers = block.num_callers.map(|n| max.max(n));
|
max_num_callers = block.num_callers.map(|n| max.max(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
max_params = max_params.max(block.params);
|
max_params = max_params.max(
|
||||||
|
block.params
|
||||||
|
+ target
|
||||||
|
.to_drop
|
||||||
|
.as_ref()
|
||||||
|
.map(|t| t.clone().count())
|
||||||
|
.unwrap_or_default() as u32
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let cc = cc.map(|(cc, to_drop)| {
|
let cc = cc.map(|cc| {
|
||||||
match cc {
|
match cc {
|
||||||
Left(cc) => Left(ctx.serialize_block_args(&cc, to_drop)),
|
Left(cc) => Left(ctx.serialize_block_args(&cc, max_params)),
|
||||||
Right(cc) => Right(cc),
|
Right(cc) => Right(cc),
|
||||||
}
|
}
|
||||||
}).unwrap_or_else(||
|
}).unwrap_or_else(||
|
||||||
@@ -604,7 +650,7 @@ where
|
|||||||
Operator::Le(SF64) => ctx.f64_le(),
|
Operator::Le(SF64) => ctx.f64_le(),
|
||||||
Operator::Drop(range) => ctx.drop(range),
|
Operator::Drop(range) => ctx.drop(range),
|
||||||
Operator::Const(val) => ctx.const_(val),
|
Operator::Const(val) => ctx.const_(val),
|
||||||
Operator::I32WrapFromI64 => {}
|
Operator::I32WrapFromI64 => ctx.i32_wrap_from_i64(),
|
||||||
Operator::I32ReinterpretFromF32 => ctx.i32_reinterpret_from_f32(),
|
Operator::I32ReinterpretFromF32 => ctx.i32_reinterpret_from_f32(),
|
||||||
Operator::I64ReinterpretFromF64 => ctx.i64_reinterpret_from_f64(),
|
Operator::I64ReinterpretFromF64 => ctx.i64_reinterpret_from_f64(),
|
||||||
Operator::F32ReinterpretFromI32 => ctx.f32_reinterpret_from_i32(),
|
Operator::F32ReinterpretFromI32 => ctx.f32_reinterpret_from_i32(),
|
||||||
|
|||||||
Reference in New Issue
Block a user