Simple preopt: fold instructions using simple algebraic identities;

This commit is contained in:
Benjamin Bouvier
2019-07-10 19:50:41 +02:00
parent 2fef2eef67
commit 23ac723d4c
2 changed files with 89 additions and 46 deletions

View File

@@ -577,52 +577,95 @@ fn simplify(pos: &mut FuncCursor, inst: Inst) {
_ => {} _ => {}
}, },
InstructionData::BinaryImm { opcode, arg, imm } => match opcode { InstructionData::BinaryImm { opcode, arg, imm } => {
Opcode::IaddImm let ty = pos.func.dfg.ctrl_typevar(inst);
| Opcode::ImulImm
| Opcode::BorImm let mut imm = imm;
| Opcode::BandImm match opcode {
| Opcode::BxorImm => { Opcode::IaddImm
// Fold binary_op(C2, binary_op(C1, x)) into binary_op(binary_op(C1 | C2), x) | Opcode::ImulImm
if let ValueDef::Result(arg_inst, _) = pos.func.dfg.value_def(arg) { | Opcode::BorImm
if let InstructionData::BinaryImm { | Opcode::BandImm
opcode: prev_opcode, | Opcode::BxorImm => {
arg: prev_arg, // Fold binary_op(C2, binary_op(C1, x)) into binary_op(binary_op(C1, C2), x)
imm: prev_imm, if let ValueDef::Result(arg_inst, _) = pos.func.dfg.value_def(arg) {
} = &pos.func.dfg[arg_inst] if let InstructionData::BinaryImm {
{ opcode: prev_opcode,
if opcode == *prev_opcode { arg: prev_arg,
let ty = pos.func.dfg.ctrl_typevar(inst); imm: prev_imm,
if ty == pos.func.dfg.ctrl_typevar(arg_inst) { } = &pos.func.dfg[arg_inst]
let lhs: i64 = imm.into(); {
let rhs: i64 = (*prev_imm).into(); if opcode == *prev_opcode {
let new_imm = match opcode { if ty == pos.func.dfg.ctrl_typevar(arg_inst) {
Opcode::BorImm => lhs | rhs, let lhs: i64 = imm.into();
Opcode::BandImm => lhs & rhs, let rhs: i64 = (*prev_imm).into();
Opcode::BxorImm => lhs ^ rhs, let new_imm = match opcode {
Opcode::IaddImm => lhs.wrapping_add(rhs), Opcode::BorImm => lhs | rhs,
Opcode::ImulImm => lhs.wrapping_mul(rhs), Opcode::BandImm => lhs & rhs,
_ => panic!("can't happen"), Opcode::BxorImm => lhs ^ rhs,
}; Opcode::IaddImm => lhs.wrapping_add(rhs),
let new_imm = immediates::Imm64::from(new_imm); Opcode::ImulImm => lhs.wrapping_mul(rhs),
let arg = *prev_arg; _ => panic!("can't happen"),
pos.func };
.dfg let new_imm = immediates::Imm64::from(new_imm);
.replace(inst) let arg = *prev_arg;
.BinaryImm(opcode, ty, new_imm, arg); pos.func
.dfg
.replace(inst)
.BinaryImm(opcode, ty, new_imm, arg);
imm = new_imm;
}
} }
} }
} }
} }
}
Opcode::UshrImm | Opcode::SshrImm => { Opcode::UshrImm | Opcode::SshrImm => {
if try_fold_extended_move(pos, inst, opcode, arg, imm) { if try_fold_extended_move(pos, inst, opcode, arg, imm) {
return;
}
}
_ => {}
};
// Replace operations that are no-ops.
match (opcode, imm.into()) {
(Opcode::IaddImm, 0)
| (Opcode::ImulImm, 1)
| (Opcode::SdivImm, 1)
| (Opcode::UdivImm, 1)
| (Opcode::BorImm, 0)
| (Opcode::BandImm, -1)
| (Opcode::BxorImm, 0)
| (Opcode::RotlImm, 0)
| (Opcode::RotrImm, 0)
| (Opcode::IshlImm, 0)
| (Opcode::UshrImm, 0)
| (Opcode::SshrImm, 0) => {
// Alias the result value with the original argument.
let results = pos.func.dfg.detach_results(inst);
debug_assert!(results.len(&pos.func.dfg.value_lists) == 1);
let first_result = results.get(0, &pos.func.dfg.value_lists).unwrap();
pos.func.dfg.change_to_alias(first_result, arg);
// Replace instruction by a nop.
pos.func.dfg.replace(inst).nop();
return; return;
} }
(Opcode::ImulImm, 0) | (Opcode::BandImm, 0) => {
// Replace by zero.
pos.func.dfg.replace(inst).iconst(ty, 0);
return;
}
(Opcode::BorImm, -1) => {
// Replace by minus one.
pos.func.dfg.replace(inst).iconst(ty, -1);
return;
}
_ => {}
} }
_ => {} }
},
InstructionData::IntCompare { opcode, cond, args } => { InstructionData::IntCompare { opcode, cond, args } => {
debug_assert_eq!(opcode, Opcode::Icmp); debug_assert_eq!(opcode, Opcode::Icmp);

View File

@@ -11,11 +11,11 @@ ebb0(v0: i32):
return v1 return v1
} }
; converted to a copy ; converted to a nop
function %t_udiv32_p1(i32) -> i32 { function %t_udiv32_p1(i32) -> i32 {
ebb0(v0: i32): ebb0(v0: i32):
v1 = udiv_imm v0, 1 v1 = udiv_imm v0, 1
; check: copy v0 ; check: nop
return v1 return v1
} }
@@ -46,11 +46,11 @@ ebb0(v0: i64):
return v1 return v1
} }
; converted to a copy ; converted to a nop
function %t_udiv64_p1(i64) -> i64 { function %t_udiv64_p1(i64) -> i64 {
ebb0(v0: i64): ebb0(v0: i64):
v1 = udiv_imm v0, 1 v1 = udiv_imm v0, 1
; check: copy v0 ; check: nop
return v1 return v1
} }
@@ -81,11 +81,11 @@ ebb0(v0: i32):
return v1 return v1
} }
; converted to a copy ; converted to a nop
function %t_sdiv32_p1(i32) -> i32 { function %t_sdiv32_p1(i32) -> i32 {
ebb0(v0: i32): ebb0(v0: i32):
v1 = sdiv_imm v0, 1 v1 = sdiv_imm v0, 1
; check: copy v0 ; check: nop
return v1 return v1
} }
@@ -192,11 +192,11 @@ ebb0(v0: i64):
return v1 return v1
} }
; converted to a copy ; converted to a nop
function %t_sdiv64_p1(i64) -> i64 { function %t_sdiv64_p1(i64) -> i64 {
ebb0(v0: i64): ebb0(v0: i64):
v1 = sdiv_imm v0, 1 v1 = sdiv_imm v0, 1
; check: copy v0 ; check: nop
return v1 return v1
} }