Fix some places that could have caused panics, update example assembly in readme
This commit is contained in:
27
README.md
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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -2098,4 +2098,3 @@ where
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user