use super::*;
pub(crate) fn expr_for_reg_use(
lowering: &ProtoLowering<'_>,
block: BlockRef,
instr_ref: InstrRef,
reg: Reg,
) -> HirExpr {
if let Some(local) = loop_local_for_reg(lowering, block, reg) {
return HirExpr::LocalRef(local);
}
let Some(values) = lowering.dataflow.use_values_at(instr_ref).get(reg) else {
return entry_reg_expr(lowering, reg);
};
if values.is_empty() {
return entry_reg_expr(lowering, reg);
}
if values.len() == 1 {
let value = values
.iter()
.next()
.expect("len checked above, exactly one SSA-like value exists");
return match value {
SsaValue::Def(def) => HirExpr::TempRef(lowering.bindings.fixed_temps[def.index()]),
SsaValue::Phi(phi) => HirExpr::TempRef(lowering.bindings.phi_temps[phi.index()]),
};
}
unresolved_expr(format!(
"multi-value use r{} @{}",
reg.index(),
instr_ref.index()
))
}
pub(crate) fn expr_for_closure_capture(
lowering: &ProtoLowering<'_>,
block: BlockRef,
instr_ref: InstrRef,
dst: Reg,
source: crate::transformer::CaptureSource,
) -> HirExpr {
match source {
crate::transformer::CaptureSource::Reg(reg) if reg == dst => {
let self_temp = lowering.bindings.instr_fixed_defs[instr_ref.index()]
.first()
.copied()
.expect("closure writes exactly one fixed target");
HirExpr::TempRef(self_temp)
}
crate::transformer::CaptureSource::Reg(reg) => {
expr_for_reg_use(lowering, block, instr_ref, reg)
}
crate::transformer::CaptureSource::Upvalue(upvalue) => {
HirExpr::UpvalueRef(UpvalueId(upvalue.index()))
}
}
}
pub(crate) fn expr_for_reg_at_block_entry(
lowering: &ProtoLowering<'_>,
block: BlockRef,
reg: Reg,
) -> HirExpr {
if let Some(local) = loop_local_for_reg(lowering, block, reg) {
return HirExpr::LocalRef(local);
}
let range = lowering.cfg.blocks[block.index()].instrs;
if range.is_empty() {
return entry_reg_expr(lowering, reg);
}
let Some(values) = lowering.dataflow.reaching_values_at(range.start).get(reg) else {
return entry_reg_expr(lowering, reg);
};
if values.is_empty() {
return entry_reg_expr(lowering, reg);
}
if values.len() == 1 {
let value = values
.iter()
.next()
.expect("len checked above, exactly one SSA-like value exists");
return match value {
SsaValue::Def(def) => HirExpr::TempRef(lowering.bindings.fixed_temps[def.index()]),
SsaValue::Phi(phi) => HirExpr::TempRef(lowering.bindings.phi_temps[phi.index()]),
};
}
unresolved_expr(format!(
"multi-value entry r{} block#{}",
reg.index(),
block.index()
))
}
pub(crate) fn expr_for_reg_at_block_exit(
lowering: &ProtoLowering<'_>,
block: BlockRef,
reg: Reg,
) -> HirExpr {
if let Some(local) = loop_local_for_reg(lowering, block, reg) {
return HirExpr::LocalRef(local);
}
let range = lowering.cfg.blocks[block.index()].instrs;
let Some(last_instr_ref) = range.last() else {
return entry_reg_expr(lowering, reg);
};
let effect = &lowering.dataflow.instr_effects[last_instr_ref.index()];
if effect.fixed_must_defs.contains(®) {
let Some(def) = fixed_def_for_reg(lowering, last_instr_ref, reg) else {
return unresolved_expr(format!(
"missing block-exit def r{} block#{}",
reg.index(),
block.index()
));
};
return HirExpr::TempRef(lowering.bindings.fixed_temps[def.index()]);
}
let mut values = lowering
.dataflow
.reaching_values_at(last_instr_ref)
.get(reg)
.map(|values| values.to_compact_set())
.unwrap_or_default();
if effect.fixed_may_defs.contains(®) {
let Some(def) = fixed_def_for_reg(lowering, last_instr_ref, reg) else {
return unresolved_expr(format!(
"missing block-exit may-def r{} block#{}",
reg.index(),
block.index()
));
};
values.insert(SsaValue::Def(def));
}
if values.is_empty() {
return entry_reg_expr(lowering, reg);
}
if values.len() == 1 {
let value = values
.iter()
.next()
.expect("len checked above, exactly one SSA-like value exists");
return match value {
SsaValue::Def(def) => HirExpr::TempRef(lowering.bindings.fixed_temps[def.index()]),
SsaValue::Phi(phi) => HirExpr::TempRef(lowering.bindings.phi_temps[phi.index()]),
};
}
unresolved_expr(format!(
"multi-value exit r{} block#{}",
reg.index(),
block.index()
))
}
pub(crate) fn expr_for_reg_use_inline(
lowering: &ProtoLowering<'_>,
block: BlockRef,
instr_ref: InstrRef,
reg: Reg,
) -> HirExpr {
if let Some(local) = loop_local_for_reg(lowering, block, reg) {
return HirExpr::LocalRef(local);
}
let Some(values) = lowering.dataflow.use_values_at(instr_ref).get(reg) else {
return entry_reg_expr(lowering, reg);
};
if values.is_empty() {
return entry_reg_expr(lowering, reg);
}
if values.len() == 1 {
let value = values
.iter()
.next()
.expect("len checked above, exactly one SSA-like value exists");
return match value {
SsaValue::Def(def) => expr_for_dup_safe_fixed_def(lowering, def)
.unwrap_or_else(|| HirExpr::TempRef(lowering.bindings.fixed_temps[def.index()])),
SsaValue::Phi(phi) => HirExpr::TempRef(lowering.bindings.phi_temps[phi.index()]),
};
}
unresolved_expr(format!(
"multi-value use r{} @{}",
reg.index(),
instr_ref.index()
))
}
pub(crate) fn expr_for_reg_use_single_eval(
lowering: &ProtoLowering<'_>,
block: BlockRef,
instr_ref: InstrRef,
reg: Reg,
) -> HirExpr {
if let Some(local) = loop_local_for_reg(lowering, block, reg) {
return HirExpr::LocalRef(local);
}
let Some(values) = lowering.dataflow.use_values_at(instr_ref).get(reg) else {
return entry_reg_expr(lowering, reg);
};
if values.is_empty() {
return entry_reg_expr(lowering, reg);
}
if values.len() == 1 {
let value = values
.iter()
.next()
.expect("len checked above, exactly one SSA-like value exists");
return match value {
SsaValue::Def(def) => expr_for_fixed_def(lowering, def)
.unwrap_or_else(|| HirExpr::TempRef(lowering.bindings.fixed_temps[def.index()])),
SsaValue::Phi(phi) => HirExpr::TempRef(lowering.bindings.phi_temps[phi.index()]),
};
}
unresolved_expr(format!(
"multi-value use r{} @{}",
reg.index(),
instr_ref.index()
))
}