diff --git a/cranelift/codegen/src/simple_preopt.rs b/cranelift/codegen/src/simple_preopt.rs index b71d4a31c4..2890cb262c 100644 --- a/cranelift/codegen/src/simple_preopt.rs +++ b/cranelift/codegen/src/simple_preopt.rs @@ -5,8 +5,9 @@ use crate::cursor::{Cursor, FuncCursor}; use crate::divconst_magic_numbers::{magic_s32, magic_s64, magic_u32, magic_u64}; use crate::divconst_magic_numbers::{MS32, MS64, MU32, MU64}; +use crate::ir::condcodes::IntCC; use crate::ir::dfg::ValueDef; -use crate::ir::instructions::Opcode; +use crate::ir::instructions::{Opcode, ValueList}; use crate::ir::types::{I32, I64}; use crate::ir::Inst; use crate::ir::{DataFlowGraph, Function, InstBuilder, InstructionData, Type, Value}; @@ -536,6 +537,88 @@ fn simplify(pos: &mut FuncCursor, inst: Inst) { } } +struct BranchOptInfo { + br_inst: Inst, + cmp_arg: Value, + destination: Ebb, + args: ValueList, + kind: BranchOptKind, +} + +enum BranchOptKind { + EqualZero, + NotEqualZero, +} + +fn branch_opt(pos: &mut FuncCursor, inst: Inst) { + let info = match pos.func.dfg[inst] { + InstructionData::BranchInt { + opcode: Opcode::Brif, + cond: br_cond, + destination, + ref args, + } => { + let first_arg = { + let args = pos.func.dfg.inst_args(inst); + args[0] + }; + if let ValueDef::Result(iconst_inst, _) = pos.func.dfg.value_def(first_arg) { + if let InstructionData::BinaryImm { + opcode: Opcode::IfcmpImm, + imm: cmp_imm, + arg: cmp_arg, + } = pos.func.dfg[iconst_inst] + { + let cmp_imm: i64 = cmp_imm.into(); + if cmp_imm != 0 { + return; + } + + match br_cond { + IntCC::NotEqual => BranchOptInfo { + br_inst: inst, + cmp_arg: cmp_arg, + destination: destination, + args: args.clone(), + kind: BranchOptKind::NotEqualZero, + }, + IntCC::Equal => BranchOptInfo { + br_inst: inst, + cmp_arg: cmp_arg, + destination: destination, + args: args.clone(), + kind: BranchOptKind::EqualZero, + }, + _ => return, + } + } else { + return; + } + } else { + return; + } + } + _ => return, + }; + + match info.kind { + BranchOptKind::EqualZero => { + let args = info.args.as_slice(&pos.func.dfg.value_lists)[1..].to_vec(); + pos.func + .dfg + .replace(info.br_inst) + .brz(info.cmp_arg, info.destination, &args); + } + BranchOptKind::NotEqualZero => { + let args = info.args.as_slice(&pos.func.dfg.value_lists)[1..].to_vec(); + pos.func + .dfg + .replace(info.br_inst) + .brnz(info.cmp_arg, info.destination, &args); + } + } +} + /// The main pre-opt pass. pub fn do_preopt(func: &mut Function) { let _tt = timing::preopt(); @@ -554,6 +637,8 @@ pub fn do_preopt(func: &mut Function) { } //-- END -- division by constants ------------------ + + branch_opt(&mut pos, inst); } } } diff --git a/cranelift/filetests/filetests/simple_preopt/branch.clif b/cranelift/filetests/filetests/simple_preopt/branch.clif new file mode 100644 index 0000000000..4701052e7f --- /dev/null +++ b/cranelift/filetests/filetests/simple_preopt/branch.clif @@ -0,0 +1,29 @@ +test simple_preopt +target x86_64 + +function %brif_to_brz_fold(i32) -> i32 { +ebb0(v0: i32): + v1 = ifcmp_imm v0, 0 + brif eq v1, ebb1 + jump ebb2 +ebb1: + v2 = iconst.i32 1 + return v2 +ebb2: + v3 = iconst.i32 2 + return v3 +} +; sameln: function %brif_to_brz_fold +; nextln: ebb0(v0: i32): +; nextln: v1 = ifcmp_imm v0, 0 +; nextln: brz v0, ebb1 +; nextln: jump ebb2 +; nextln: +; nextln: ebb1: +; nextln: v2 = iconst.i32 1 +; nextln: return v2 +; nextln: +; nextln: ebb2: +; nextln: v3 = iconst.i32 2 +; nextln: return v3 +; nextln: }