use crate::ir::Expr;
pub(super) fn simplify_select(cond: &Expr, true_val: &Expr, false_val: &Expr) -> Option<Expr> {
use crate::ir::UnOp;
match cond {
Expr::LitBool(true) => Some(true_val.clone()),
Expr::LitBool(false) => Some(false_val.clone()),
Expr::LitU32(value) => {
if *value == 0 {
Some(false_val.clone())
} else {
Some(true_val.clone())
}
}
_ => {
if true_val == false_val {
return Some(true_val.clone());
}
if let Expr::UnOp {
op: UnOp::LogicalNot,
operand: inner_cond,
} = cond
{
return Some(Expr::select(
inner_cond.as_ref().clone(),
false_val.clone(),
true_val.clone(),
));
}
if matches!(true_val, Expr::LitU32(1)) && matches!(false_val, Expr::LitU32(0)) {
return Some(Expr::Cast {
target: crate::ir::DataType::U32,
value: Box::new(cond.clone()),
});
}
if matches!(true_val, Expr::LitU32(0)) && matches!(false_val, Expr::LitU32(1)) {
return Some(Expr::Cast {
target: crate::ir::DataType::U32,
value: Box::new(Expr::UnOp {
op: UnOp::LogicalNot,
operand: Box::new(cond.clone()),
}),
});
}
if let Expr::Select {
cond: inner_cond,
true_val: inner_true,
..
} = true_val
{
if inner_cond.as_ref() == cond {
return Some(Expr::select(
cond.clone(),
inner_true.as_ref().clone(),
false_val.clone(),
));
}
}
if let Expr::Select {
cond: inner_cond,
false_val: inner_false,
..
} = false_val
{
if inner_cond.as_ref() == cond {
return Some(Expr::select(
cond.clone(),
true_val.clone(),
inner_false.as_ref().clone(),
));
}
}
None
}
}
}