diff options
| author | bjorn3 <bjorn3@users.noreply.github.com> | 2020-08-30 13:02:53 +0200 |
|---|---|---|
| committer | bjorn3 <bjorn3@users.noreply.github.com> | 2020-08-30 13:15:53 +0200 |
| commit | 3b0f3a0a1e25e2ac207c99492fd2a0f6fc356f35 (patch) | |
| tree | 1c59f3a2519db5debf3bed878c955aa018d57a58 /src/optimize | |
| parent | a8e3f592c9ccbc49bf95c33dec8c2d4852a3faee (diff) | |
| download | rust-3b0f3a0a1e25e2ac207c99492fd2a0f6fc356f35.tar.gz rust-3b0f3a0a1e25e2ac207c99492fd2a0f6fc356f35.zip | |
Optimize SwitchInt for bools
Diffstat (limited to 'src/optimize')
| -rw-r--r-- | src/optimize/mod.rs | 1 | ||||
| -rw-r--r-- | src/optimize/peephole.rs | 83 |
2 files changed, 84 insertions, 0 deletions
diff --git a/src/optimize/mod.rs b/src/optimize/mod.rs index 33d75b36d96..ae969279089 100644 --- a/src/optimize/mod.rs +++ b/src/optimize/mod.rs @@ -1,6 +1,7 @@ use crate::prelude::*; mod code_layout; +pub(crate) mod peephole; mod stack2reg; pub(crate) fn optimize_function<'tcx>( diff --git a/src/optimize/peephole.rs b/src/optimize/peephole.rs new file mode 100644 index 00000000000..f8e0f3af3d0 --- /dev/null +++ b/src/optimize/peephole.rs @@ -0,0 +1,83 @@ +//! Peephole optimizations that can be performed while creating clif ir. + +use cranelift_codegen::ir::{ + condcodes::IntCC, types, InstBuilder, InstructionData, Opcode, Value, ValueDef, +}; +use cranelift_frontend::FunctionBuilder; + +/// If the given value was produced by a `bint` instruction, return it's input, otherwise return the +/// given value. +pub(crate) fn maybe_unwrap_bint(bcx: &mut FunctionBuilder<'_>, arg: Value) -> Value { + if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) { + match bcx.func.dfg[arg_inst] { + InstructionData::Unary { + opcode: Opcode::Bint, + arg, + } => arg, + _ => arg, + } + } else { + arg + } +} + +/// If the given value was produced by the lowering of `Rvalue::Not` return the input and true, +/// otherwise return the given value and false. +pub(crate) fn maybe_unwrap_bool_not(bcx: &mut FunctionBuilder<'_>, arg: Value) -> (Value, bool) { + if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) { + match bcx.func.dfg[arg_inst] { + // This is the lowering of `Rvalue::Not` + InstructionData::IntCompareImm { + opcode: Opcode::IcmpImm, + cond: IntCC::Equal, + arg, + imm, + } if imm.bits() == 0 => (arg, true), + _ => (arg, false), + } + } else { + (arg, false) + } +} + +pub(crate) fn make_branchable_value(bcx: &mut FunctionBuilder<'_>, arg: Value) -> Value { + if bcx.func.dfg.value_type(arg).is_bool() { + return arg; + } + + (|| { + let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) { + arg_inst + } else { + return None; + }; + + match bcx.func.dfg[arg_inst] { + // This is the lowering of Rvalue::Not + InstructionData::Load { + opcode: Opcode::Load, + arg: ptr, + flags, + offset, + } => { + // Using `load.i8 + uextend.i32` would legalize to `uload8 + ireduce.i8 + + // uextend.i32`. Just `uload8` is much faster. + match bcx.func.dfg.ctrl_typevar(arg_inst) { + types::I8 => Some(bcx.ins().uload8(types::I32, flags, ptr, offset)), + types::I16 => Some(bcx.ins().uload16(types::I32, flags, ptr, offset)), + _ => None, + } + } + _ => None, + } + })() + .unwrap_or_else(|| { + match bcx.func.dfg.value_type(arg) { + types::I8 | types::I32 => { + // WORKAROUND for brz.i8 and brnz.i8 not yet being implemented + bcx.ins().uextend(types::I32, arg) + } + _ => arg, + } + }) +} |
