Browse Source

Fix some places that could have caused panics, update example assembly in readme

pull/397/head
Jef 6 years ago
parent
commit
652e2fdeec
  1. 27
      README.md
  2. 85
      src/backend.rs
  3. 24
      src/function_body.rs
  4. 1
      src/microwasm.rs

27
README.md

@ -127,37 +127,32 @@ fib:
ret ret
``` ```
Whereas Lightbeam produces code with far fewer memory accesses than both (and fewer blocks than FireFox's output): Whereas Lightbeam produces smaller code with far fewer memory accesses than both (and fewer blocks than FireFox's output):
```asm ```asm
fib: fib:
xor eax, eax
cmp esi, 2 cmp esi, 2
setb al mov eax, 1
mov ecx, 1 jb .Lreturn
test eax, eax
jne .Lreturn
mov eax, 1 mov eax, 1
.Lloop: .Lloop:
mov rcx, rsi mov rcx, rsi
add ecx, 0xffffffff add ecx, 0xffffffff
push rsi push rsi
push rax push rax
push rax
mov rsi, rcx mov rsi, rcx
call 0 call fib
add eax, dword ptr [rsp] add eax, dword ptr [rsp + 8]
mov rcx, qword ptr [rsp + 8] mov rcx, qword ptr [rsp + 0x10]
add ecx, 0xfffffffe add ecx, 0xfffffffe
xor edx, edx
cmp ecx, 1 cmp ecx, 1
seta dl
mov rsi, rcx mov rsi, rcx
add rsp, 0x10 pop rcx
test edx, edx pop rcx
jne .Lloop pop rcx
mov rcx, rax ja .Lloop
.Lreturn: .Lreturn:
mov rax, rcx
ret ret
``` ```

85
src/backend.rs

@ -2362,6 +2362,38 @@ impl<'this, M: ModuleContext> Context<'this, M> {
} }
} }
pub fn serialize_block_args(
&mut self,
cc: &BlockCallingConvention,
other_to_drop: Option<RangeInclusive<u32>>,
) -> BlockCallingConvention {
self.do_pass_block_args(cc);
let mut out_args = cc.arguments.clone();
out_args.reverse();
if let Some(to_drop) = other_to_drop {
for _ in to_drop {
let val = self.pop();
// TODO: We can use stack slots for values already on the stack but we
// don't refcount stack slots right now
let loc = CCLoc::Reg(self.into_temp_reg(None, val));
out_args.push(loc);
}
}
out_args.reverse();
self.set_stack_depth(cc.stack_depth);
BlockCallingConvention {
stack_depth: cc.stack_depth,
arguments: out_args,
}
}
/// Puts all stack values into "real" locations so that they can i.e. be set to different /// Puts all stack values into "real" locations so that they can i.e. be set to different
/// values on different iterations of a loop /// values on different iterations of a loop
pub fn serialize_args(&mut self, count: u32) -> BlockCallingConvention { pub fn serialize_args(&mut self, count: u32) -> BlockCallingConvention {
@ -3670,6 +3702,58 @@ impl<'this, M: ModuleContext> Context<'this, M> {
self.push(out_val); self.push(out_val);
} }
pub fn i32_reinterpret_from_f32(&mut self) {
let val = self.pop();
let out = match val {
ValueLocation::Immediate(imm) => {
ValueLocation::Immediate(imm.as_f32().unwrap().bits().into())
}
val => val,
};
self.push(out);
}
pub fn i64_reinterpret_from_f64(&mut self) {
let val = self.pop();
let out = match val {
ValueLocation::Immediate(imm) => {
ValueLocation::Immediate(imm.as_f64().unwrap().bits().into())
}
val => val,
};
self.push(out);
}
pub fn f32_reinterpret_from_i32(&mut self) {
let val = self.pop();
let out = match val {
ValueLocation::Immediate(imm) => {
ValueLocation::Immediate(wasmparser::Ieee32(imm.as_i32().unwrap() as _).into())
}
val => val,
};
self.push(out);
}
pub fn f64_reinterpret_from_i64(&mut self) {
let val = self.pop();
let out = match val {
ValueLocation::Immediate(imm) => {
ValueLocation::Immediate(wasmparser::Ieee64(imm.as_i64().unwrap() as _).into())
}
val => val,
};
self.push(out);
}
unop!(i64_popcnt, popcnt, Rq, u64, |a: u64| a.count_ones() as u64); unop!(i64_popcnt, popcnt, Rq, u64, |a: u64| a.count_ones() as u64);
// TODO: Use `lea` when the LHS operand isn't a temporary but both of the operands // TODO: Use `lea` when the LHS operand isn't a temporary but both of the operands
@ -4970,4 +5054,3 @@ impl IntoLabel for (LabelValue, LabelValue) {
Box::new(const_values(self.0, self.1)) Box::new(const_values(self.0, self.1))
} }
} }

24
src/function_body.rs

@ -409,7 +409,9 @@ where
if block.calling_convention.is_some() { if block.calling_convention.is_some() {
assert!(cc.is_none(), "Can't pass different params to different elements of `br_table` yet"); assert!(cc.is_none(), "Can't pass different params to different elements of `br_table` yet");
cc = block.calling_convention.clone(); cc = block.calling_convention
.clone()
.map(|cc| (cc, target.to_drop.clone()));
} }
if let Some(max) = max_num_callers { if let Some(max) = max_num_callers {
@ -419,11 +421,12 @@ where
max_params = max_params.max(block.params); max_params = max_params.max(block.params);
} }
if let Some(Left(cc)) = &cc { let cc = cc.map(|(cc, to_drop)| {
ctx.pass_block_args(cc); match cc {
} Left(cc) => Left(ctx.serialize_block_args(&cc, to_drop)),
Right(cc) => Right(cc),
let cc = cc.unwrap_or_else(|| }
}).unwrap_or_else(||
if max_num_callers.map(|callers| callers <= 1).unwrap_or(false) { if max_num_callers.map(|callers| callers <= 1).unwrap_or(false) {
Right(ctx.virtual_calling_convention()) Right(ctx.virtual_calling_convention())
} else { } else {
@ -547,11 +550,10 @@ where
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 => {}
// All reinterpret operators are no-ops - we do the conversion at the point of usage. Operator::I32ReinterpretFromF32 => ctx.i32_reinterpret_from_f32(),
Operator::I32ReinterpretFromF32 => {} Operator::I64ReinterpretFromF64 => ctx.i64_reinterpret_from_f64(),
Operator::I64ReinterpretFromF64 => {} Operator::F32ReinterpretFromI32 => ctx.f32_reinterpret_from_i32(),
Operator::F32ReinterpretFromI32 => {} Operator::F64ReinterpretFromI64 => ctx.f64_reinterpret_from_i64(),
Operator::F64ReinterpretFromI64 => {}
Operator::ITruncFromF { Operator::ITruncFromF {
input_ty: Size::_32, input_ty: Size::_32,
output_ty: sint::I32, output_ty: sint::I32,

1
src/microwasm.rs

@ -2098,4 +2098,3 @@ where
})) }))
} }
} }

Loading…
Cancel
Save