Rename the 'cretonne' crate to 'cretonne-codegen'.
This fixes the next part of #287.
This commit is contained in:
203
lib/codegen/src/postopt.rs
Normal file
203
lib/codegen/src/postopt.rs
Normal file
@@ -0,0 +1,203 @@
|
||||
//! A post-legalization rewriting pass.
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use cursor::{Cursor, EncCursor};
|
||||
use ir::condcodes::{CondCode, FloatCC, IntCC};
|
||||
use ir::dfg::ValueDef;
|
||||
use ir::immediates::Imm64;
|
||||
use ir::instructions::{Opcode, ValueList};
|
||||
use ir::{Ebb, Function, Inst, InstBuilder, InstructionData, Value};
|
||||
use isa::TargetIsa;
|
||||
use timing;
|
||||
|
||||
/// Information collected about a compare+branch sequence.
|
||||
struct CmpBrInfo {
|
||||
/// The branch instruction.
|
||||
br_inst: Inst,
|
||||
/// The icmp, icmp_imm, or fcmp instruction.
|
||||
cmp_inst: Inst,
|
||||
/// The destination of the branch.
|
||||
destination: Ebb,
|
||||
/// The arguments of the branch.
|
||||
args: ValueList,
|
||||
/// The first argument to the comparison. The second is in the `kind` field.
|
||||
cmp_arg: Value,
|
||||
/// If the branch is `brz` rather than `brnz`, we need to invert the condition
|
||||
/// before the branch.
|
||||
invert_branch_cond: bool,
|
||||
/// The kind of comparison, and the second argument.
|
||||
kind: CmpBrKind,
|
||||
}
|
||||
|
||||
enum CmpBrKind {
|
||||
Icmp { cond: IntCC, arg: Value },
|
||||
IcmpImm { cond: IntCC, imm: Imm64 },
|
||||
Fcmp { cond: FloatCC, arg: Value },
|
||||
}
|
||||
|
||||
/// Optimize comparisons to use flags values, to avoid materializing conditions
|
||||
/// in integer registers.
|
||||
///
|
||||
/// For example, optimize icmp/fcmp brz/brnz sequences into ifcmp/ffcmp brif/brff
|
||||
/// sequences.
|
||||
fn optimize_cpu_flags(
|
||||
pos: &mut EncCursor,
|
||||
inst: Inst,
|
||||
last_flags_clobber: Option<Inst>,
|
||||
isa: &TargetIsa,
|
||||
) {
|
||||
// Look for compare and branch patterns.
|
||||
// This code could be considerably simplified with non-lexical lifetimes.
|
||||
let info = match pos.func.dfg[inst] {
|
||||
InstructionData::Branch {
|
||||
opcode,
|
||||
destination,
|
||||
ref args,
|
||||
} => {
|
||||
let first_arg = args.first(&pos.func.dfg.value_lists).unwrap();
|
||||
let invert_branch_cond = match opcode {
|
||||
Opcode::Brz => true,
|
||||
Opcode::Brnz => false,
|
||||
_ => panic!(),
|
||||
};
|
||||
if let ValueDef::Result(cond_inst, _) = pos.func.dfg.value_def(first_arg) {
|
||||
match pos.func.dfg[cond_inst] {
|
||||
InstructionData::IntCompare {
|
||||
cond,
|
||||
args: cmp_args,
|
||||
..
|
||||
} => CmpBrInfo {
|
||||
br_inst: inst,
|
||||
cmp_inst: cond_inst,
|
||||
destination,
|
||||
args: args.clone(),
|
||||
cmp_arg: cmp_args[0],
|
||||
invert_branch_cond,
|
||||
kind: CmpBrKind::Icmp {
|
||||
cond,
|
||||
arg: cmp_args[1],
|
||||
},
|
||||
},
|
||||
InstructionData::IntCompareImm {
|
||||
cond,
|
||||
arg: cmp_arg,
|
||||
imm: cmp_imm,
|
||||
..
|
||||
} => CmpBrInfo {
|
||||
br_inst: inst,
|
||||
cmp_inst: cond_inst,
|
||||
destination,
|
||||
args: args.clone(),
|
||||
cmp_arg,
|
||||
invert_branch_cond,
|
||||
kind: CmpBrKind::IcmpImm { cond, imm: cmp_imm },
|
||||
},
|
||||
InstructionData::FloatCompare {
|
||||
cond,
|
||||
args: cmp_args,
|
||||
..
|
||||
} => CmpBrInfo {
|
||||
br_inst: inst,
|
||||
cmp_inst: cond_inst,
|
||||
destination,
|
||||
args: args.clone(),
|
||||
cmp_arg: cmp_args[0],
|
||||
invert_branch_cond,
|
||||
kind: CmpBrKind::Fcmp {
|
||||
cond,
|
||||
arg: cmp_args[1],
|
||||
},
|
||||
},
|
||||
_ => return,
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TODO: trapif, trueif, selectif, and their ff counterparts.
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// If any instructions clobber the flags between the comparison and the branch,
|
||||
// don't optimize them.
|
||||
if last_flags_clobber != Some(info.cmp_inst) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We found a compare+branch pattern. Transform it to use flags.
|
||||
let args = info.args.as_slice(&pos.func.dfg.value_lists)[1..].to_vec();
|
||||
pos.goto_inst(info.cmp_inst);
|
||||
match info.kind {
|
||||
CmpBrKind::Icmp { mut cond, arg } => {
|
||||
let flags = pos.ins().ifcmp(info.cmp_arg, arg);
|
||||
pos.func.dfg.replace(info.cmp_inst).trueif(cond, flags);
|
||||
if info.invert_branch_cond {
|
||||
cond = cond.inverse();
|
||||
}
|
||||
pos.func.dfg.replace(info.br_inst).brif(
|
||||
cond,
|
||||
flags,
|
||||
info.destination,
|
||||
&args,
|
||||
);
|
||||
}
|
||||
CmpBrKind::IcmpImm { mut cond, imm } => {
|
||||
let flags = pos.ins().ifcmp_imm(info.cmp_arg, imm);
|
||||
pos.func.dfg.replace(info.cmp_inst).trueif(cond, flags);
|
||||
if info.invert_branch_cond {
|
||||
cond = cond.inverse();
|
||||
}
|
||||
pos.func.dfg.replace(info.br_inst).brif(
|
||||
cond,
|
||||
flags,
|
||||
info.destination,
|
||||
&args,
|
||||
);
|
||||
}
|
||||
CmpBrKind::Fcmp { mut cond, arg } => {
|
||||
let flags = pos.ins().ffcmp(info.cmp_arg, arg);
|
||||
pos.func.dfg.replace(info.cmp_inst).trueff(cond, flags);
|
||||
if info.invert_branch_cond {
|
||||
cond = cond.inverse();
|
||||
}
|
||||
pos.func.dfg.replace(info.br_inst).brff(
|
||||
cond,
|
||||
flags,
|
||||
info.destination,
|
||||
&args,
|
||||
);
|
||||
}
|
||||
}
|
||||
pos.func.update_encoding(info.cmp_inst, isa).is_ok();
|
||||
pos.func.update_encoding(info.br_inst, isa).is_ok();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// The main post-opt pass.
|
||||
|
||||
pub fn do_postopt(func: &mut Function, isa: &TargetIsa) {
|
||||
let _tt = timing::postopt();
|
||||
let mut pos = EncCursor::new(func, isa);
|
||||
while let Some(_ebb) = pos.next_ebb() {
|
||||
let mut last_flags_clobber = None;
|
||||
while let Some(inst) = pos.next_inst() {
|
||||
if isa.uses_cpu_flags() {
|
||||
// Optimize instructions to make use of flags.
|
||||
optimize_cpu_flags(&mut pos, inst, last_flags_clobber, isa);
|
||||
|
||||
// Track the most recent seen instruction that clobbers the flags.
|
||||
if let Some(constraints) =
|
||||
isa.encoding_info().operand_constraints(
|
||||
pos.func.encodings[inst],
|
||||
)
|
||||
{
|
||||
if constraints.clobbers_flags {
|
||||
last_flags_clobber = Some(inst)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user