about summary refs log tree commit diff
path: root/src/optimize
diff options
context:
space:
mode:
authorbjorn3 <bjorn3@users.noreply.github.com>2020-08-30 13:02:53 +0200
committerbjorn3 <bjorn3@users.noreply.github.com>2020-08-30 13:15:53 +0200
commit3b0f3a0a1e25e2ac207c99492fd2a0f6fc356f35 (patch)
tree1c59f3a2519db5debf3bed878c955aa018d57a58 /src/optimize
parenta8e3f592c9ccbc49bf95c33dec8c2d4852a3faee (diff)
downloadrust-3b0f3a0a1e25e2ac207c99492fd2a0f6fc356f35.tar.gz
rust-3b0f3a0a1e25e2ac207c99492fd2a0f6fc356f35.zip
Optimize SwitchInt for bools
Diffstat (limited to 'src/optimize')
-rw-r--r--src/optimize/mod.rs1
-rw-r--r--src/optimize/peephole.rs83
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,
+        }
+    })
+}