Avoid emitting tests on select

This commit is contained in:
Jef
2019-04-17 15:47:22 +02:00
parent ced654f907
commit 82e810c8d2

View File

@@ -330,7 +330,9 @@ impl Registers {
pub fn release(&mut self, gpr: GPR) { pub fn release(&mut self, gpr: GPR) {
let (gpr, scratch_counts) = self.scratch_counts_mut(gpr); let (gpr, scratch_counts) = self.scratch_counts_mut(gpr);
let c = &mut scratch_counts.1[gpr as usize]; let c = &mut scratch_counts.1[gpr as usize];
*c = c.checked_sub(1).unwrap_or_else(|| panic!("Double-freed register: {}", gpr)); *c = c
.checked_sub(1)
.unwrap_or_else(|| panic!("Double-freed register: {}", gpr));
if *c == 0 { if *c == 0 {
scratch_counts.0.release(gpr); scratch_counts.0.release(gpr);
} }
@@ -4342,6 +4344,119 @@ impl<'this, M: ModuleContext> Context<'this, M> {
self.free_value(right); self.free_value(right);
} }
fn cmov(&mut self, cond_code: CondCode, dst: GPR, src: CCLoc) {
match src {
CCLoc::Reg(reg) => match cond_code {
cc::EQUAL => {
dynasm!(self.asm
; cmove Rq(dst.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
cc::NOT_EQUAL => {
dynasm!(self.asm
; cmovne Rq(dst.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
cc::GE_U => {
dynasm!(self.asm
; cmovae Rq(dst.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
cc::LT_U => {
dynasm!(self.asm
; cmovb Rq(dst.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
cc::GT_U => {
dynasm!(self.asm
; cmova Rq(dst.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
cc::LE_U => {
dynasm!(self.asm
; cmovbe Rq(dst.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
cc::GE_S => {
dynasm!(self.asm
; cmovge Rq(dst.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
cc::LT_S => {
dynasm!(self.asm
; cmovl Rq(dst.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
cc::GT_S => {
dynasm!(self.asm
; cmovg Rq(dst.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
cc::LE_S => {
dynasm!(self.asm
; cmovle Rq(dst.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
},
CCLoc::Stack(offset) => {
let offset = self.adjusted_offset(offset);
match cond_code {
cc::EQUAL => {
dynasm!(self.asm
; cmove Rq(dst.rq().unwrap()), [rsp + offset]
);
}
cc::NOT_EQUAL => {
dynasm!(self.asm
; cmovne Rq(dst.rq().unwrap()), [rsp + offset]
);
}
cc::GE_U => {
dynasm!(self.asm
; cmovae Rq(dst.rq().unwrap()), [rsp + offset]
);
}
cc::LT_U => {
dynasm!(self.asm
; cmovb Rq(dst.rq().unwrap()), [rsp + offset]
);
}
cc::GT_U => {
dynasm!(self.asm
; cmova Rq(dst.rq().unwrap()), [rsp + offset]
);
}
cc::LE_U => {
dynasm!(self.asm
; cmovbe Rq(dst.rq().unwrap()), [rsp + offset]
);
}
cc::GE_S => {
dynasm!(self.asm
; cmovge Rq(dst.rq().unwrap()), [rsp + offset]
);
}
cc::LT_S => {
dynasm!(self.asm
; cmovl Rq(dst.rq().unwrap()), [rsp + offset]
);
}
cc::GT_S => {
dynasm!(self.asm
; cmovg Rq(dst.rq().unwrap()), [rsp + offset]
);
}
cc::LE_S => {
dynasm!(self.asm
; cmovle Rq(dst.rq().unwrap()), [rsp + offset]
);
}
}
}
}
}
pub fn select(&mut self) { pub fn select(&mut self) {
let cond = self.pop(); let cond = self.pop();
let else_ = self.pop(); let else_ = self.pop();
@@ -4357,103 +4472,52 @@ impl<'this, M: ModuleContext> Context<'this, M> {
return; return;
} }
let cond_reg = self.into_reg(I32, cond).unwrap(); let cond_code = match cond {
let else_ = if let ValueLocation::Stack(_) = else_ { ValueLocation::Cond(cc) => cc,
else_ _ => {
} else { let cond_reg = self.into_reg(I32, cond).unwrap();
ValueLocation::Reg(self.into_reg(I32, else_).unwrap()) dynasm!(self.asm
; test Rd(cond_reg.rq().unwrap()), Rd(cond_reg.rq().unwrap())
);
self.block_state.regs.release(cond_reg);
cc::NOT_EQUAL
}
}; };
let then = if let ValueLocation::Stack(_) = then { let else_ = if let ValueLocation::Stack(offset) = else_ {
then CCLoc::Stack(offset)
} else { } else {
ValueLocation::Reg(self.into_reg(I32, then).unwrap()) CCLoc::Reg(self.into_reg(I32, else_).unwrap())
}; };
dynasm!(self.asm let then = if let ValueLocation::Stack(offset) = then {
; test Rd(cond_reg.rq().unwrap()), Rd(cond_reg.rq().unwrap()) CCLoc::Stack(offset)
); } else {
CCLoc::Reg(self.into_reg(I32, then).unwrap())
self.block_state.regs.release(cond_reg); };
let out_gpr = match (then, else_) { let out_gpr = match (then, else_) {
(ValueLocation::Reg(then_reg), else_) (CCLoc::Reg(then_reg), else_) if self.block_state.regs.num_usages(then_reg) <= 1 => {
if self.block_state.regs.num_usages(then_reg) <= 1 => self.cmov(!cond_code, then_reg, else_);
{ self.free_value(else_.into());
match else_ {
ValueLocation::Reg(reg) => {
dynasm!(self.asm
; cmovz Rq(then_reg.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
ValueLocation::Stack(offset) => {
let offset = self.adjusted_offset(offset);
dynasm!(self.asm
; cmovz Rq(then_reg.rq().unwrap()), [rsp + offset]
);
}
_ => unreachable!(),
}
self.free_value(else_);
then_reg then_reg
} }
(then, ValueLocation::Reg(else_reg)) (then, CCLoc::Reg(else_reg)) if self.block_state.regs.num_usages(else_reg) <= 1 => {
if self.block_state.regs.num_usages(else_reg) <= 1 => self.cmov(cond_code, else_reg, then);
{ self.free_value(then.into());
match then {
ValueLocation::Reg(reg) => {
dynasm!(self.asm
; cmovnz Rq(else_reg.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
ValueLocation::Stack(offset) => {
let offset = self.adjusted_offset(offset);
dynasm!(self.asm
; cmovnz Rq(else_reg.rq().unwrap()), [rsp + offset]
);
}
_ => unreachable!(),
}
self.free_value(then);
else_reg else_reg
} }
(then, else_) => { (then, else_) => {
let out = self.take_reg(GPRType::Rq).unwrap(); let out = self.take_reg(GPRType::Rq).unwrap();
match else_ { self.cmov(!cond_code, out, else_);
ValueLocation::Reg(reg) => { self.cmov(cond_code, out, then);
dynasm!(self.asm
; cmovz Rq(out.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
ValueLocation::Stack(offset) => {
let offset = self.adjusted_offset(offset);
dynasm!(self.asm
; cmovz Rq(out.rq().unwrap()), [rsp + offset]
);
}
_ => unreachable!(),
}
match then {
ValueLocation::Reg(reg) => {
dynasm!(self.asm
; cmovnz Rq(out.rq().unwrap()), Rq(reg.rq().unwrap())
);
}
ValueLocation::Stack(offset) => {
let offset = self.adjusted_offset(offset);
dynasm!(self.asm
; cmovnz Rq(out.rq().unwrap()), [rsp + offset]
);
}
_ => unreachable!(),
}
self.free_value(then); self.free_value(then.into());
self.free_value(else_); self.free_value(else_.into());
out out
} }