]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / compiler / rustc_codegen_cranelift / src / optimize / peephole.rs
CommitLineData
29967ef6
XL
1//! Peephole optimizations that can be performed while creating clif ir.
2
3use cranelift_codegen::ir::{
4 condcodes::IntCC, types, InstBuilder, InstructionData, Opcode, Value, ValueDef,
5};
6use cranelift_frontend::FunctionBuilder;
7
8/// If the given value was produced by a `bint` instruction, return it's input, otherwise return the
9/// given value.
10pub(crate) fn maybe_unwrap_bint(bcx: &mut FunctionBuilder<'_>, arg: Value) -> Value {
11 if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
12 match bcx.func.dfg[arg_inst] {
6a06907d 13 InstructionData::Unary { opcode: Opcode::Bint, arg } => arg,
29967ef6
XL
14 _ => arg,
15 }
16 } else {
17 arg
18 }
19}
20
21/// If the given value was produced by the lowering of `Rvalue::Not` return the input and true,
22/// otherwise return the given value and false.
23pub(crate) fn maybe_unwrap_bool_not(bcx: &mut FunctionBuilder<'_>, arg: Value) -> (Value, bool) {
24 if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
25 match bcx.func.dfg[arg_inst] {
26 // This is the lowering of `Rvalue::Not`
27 InstructionData::IntCompareImm {
28 opcode: Opcode::IcmpImm,
29 cond: IntCC::Equal,
30 arg,
31 imm,
32 } if imm.bits() == 0 => (arg, true),
33 _ => (arg, false),
34 }
35 } else {
36 (arg, false)
37 }
38}
39
40pub(crate) fn make_branchable_value(bcx: &mut FunctionBuilder<'_>, arg: Value) -> Value {
41 if bcx.func.dfg.value_type(arg).is_bool() {
42 return arg;
43 }
44
45 (|| {
46 let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
47 arg_inst
48 } else {
49 return None;
50 };
51
52 match bcx.func.dfg[arg_inst] {
53 // This is the lowering of Rvalue::Not
6a06907d 54 InstructionData::Load { opcode: Opcode::Load, arg: ptr, flags, offset } => {
29967ef6
XL
55 // Using `load.i8 + uextend.i32` would legalize to `uload8 + ireduce.i8 +
56 // uextend.i32`. Just `uload8` is much faster.
57 match bcx.func.dfg.ctrl_typevar(arg_inst) {
58 types::I8 => Some(bcx.ins().uload8(types::I32, flags, ptr, offset)),
59 types::I16 => Some(bcx.ins().uload16(types::I32, flags, ptr, offset)),
60 _ => None,
61 }
62 }
63 _ => None,
64 }
65 })()
66 .unwrap_or_else(|| {
67 match bcx.func.dfg.value_type(arg) {
5869c6ff 68 types::I8 | types::I16 => {
29967ef6
XL
69 // WORKAROUND for brz.i8 and brnz.i8 not yet being implemented
70 bcx.ins().uextend(types::I32, arg)
71 }
72 _ => arg,
73 }
74 })
75}
5869c6ff
XL
76
77/// Returns whether the branch is statically known to be taken or `None` if it isn't statically known.
78pub(crate) fn maybe_known_branch_taken(
79 bcx: &FunctionBuilder<'_>,
80 arg: Value,
81 test_zero: bool,
82) -> Option<bool> {
83 let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
84 arg_inst
85 } else {
86 return None;
87 };
88
89 match bcx.func.dfg[arg_inst] {
6a06907d 90 InstructionData::UnaryBool { opcode: Opcode::Bconst, imm } => {
5869c6ff
XL
91 if test_zero {
92 Some(!imm)
93 } else {
94 Some(imm)
95 }
96 }
6a06907d 97 InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => {
5869c6ff
XL
98 if test_zero {
99 Some(imm.bits() == 0)
100 } else {
101 Some(imm.bits() != 0)
102 }
103 }
104 _ => None,
105 }
106}