Stop calling Value::new_direct.
We only ever create table values now. Simplify legalizer::legalize_inst_results. Instead of calling detach_secondary_results, just detach all the results and don't treat the first result specially.
This commit is contained in:
@@ -34,9 +34,8 @@ ebb0:
|
|||||||
; check: $ebb0:
|
; check: $ebb0:
|
||||||
; nextln: $(v1l=$V), $(v1h=$V) = call $fn1()
|
; nextln: $(v1l=$V), $(v1h=$V) = call $fn1()
|
||||||
; check: $(v1new=$V) = iconcat $v1l, $v1h
|
; check: $(v1new=$V) = iconcat $v1l, $v1h
|
||||||
; check: $v1 = copy $v1new
|
|
||||||
jump ebb1(v1)
|
jump ebb1(v1)
|
||||||
; The v1 copy gets resolved by split::simplify_branch_arguments().
|
; The v1 alias gets resolved by split::simplify_branch_arguments().
|
||||||
; check: jump $ebb1($v1new)
|
; check: jump $ebb1($v1new)
|
||||||
|
|
||||||
ebb1(v10: i64):
|
ebb1(v10: i64):
|
||||||
@@ -77,9 +76,8 @@ ebb0:
|
|||||||
; check: $ebb0:
|
; check: $ebb0:
|
||||||
; nextln: $(rv=$V) = call $fn1()
|
; nextln: $(rv=$V) = call $fn1()
|
||||||
; check: $(v1new=$V) = ireduce.i8 $rv
|
; check: $(v1new=$V) = ireduce.i8 $rv
|
||||||
; check: $v1 = copy $v1new
|
|
||||||
jump ebb1(v1)
|
jump ebb1(v1)
|
||||||
; The v1 copy gets resolved by split::simplify_branch_arguments().
|
; The v1 alias gets resolved by split::simplify_branch_arguments().
|
||||||
; check: jump $ebb1($v1new)
|
; check: jump $ebb1($v1new)
|
||||||
|
|
||||||
ebb1(v10: i8):
|
ebb1(v10: i8):
|
||||||
|
|||||||
@@ -454,8 +454,14 @@ impl DataFlowGraph {
|
|||||||
*self.insts[inst].first_type_mut() = first_type.unwrap_or_default();
|
*self.insts[inst].first_type_mut() = first_type.unwrap_or_default();
|
||||||
|
|
||||||
// Include the first result in the results vector.
|
// Include the first result in the results vector.
|
||||||
if first_type.is_some() {
|
if let Some(ty) = first_type {
|
||||||
self.results[inst].push(Value::new_direct(inst), &mut self.value_lists);
|
let v = self.make_value(ValueData::Inst {
|
||||||
|
ty: ty,
|
||||||
|
num: 0,
|
||||||
|
inst: inst,
|
||||||
|
next: head.into(),
|
||||||
|
});
|
||||||
|
self.results[inst].push(v, &mut self.value_lists);
|
||||||
}
|
}
|
||||||
self.results[inst]
|
self.results[inst]
|
||||||
.as_mut_slice(&mut self.value_lists)
|
.as_mut_slice(&mut self.value_lists)
|
||||||
@@ -489,11 +495,10 @@ impl DataFlowGraph {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let first = self.results[inst].first(&mut self.value_lists).unwrap();
|
||||||
let second = self.results[inst].get(1, &mut self.value_lists);
|
let second = self.results[inst].get(1, &mut self.value_lists);
|
||||||
self.results[inst].clear(&mut self.value_lists);
|
self.results[inst].clear(&mut self.value_lists);
|
||||||
if !self.insts[inst].first_type().is_void() {
|
self.results[inst].push(first, &mut self.value_lists);
|
||||||
self.results[inst].push(Value::new_direct(inst), &mut self.value_lists);
|
|
||||||
}
|
|
||||||
second
|
second
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,21 +654,36 @@ impl DataFlowGraph {
|
|||||||
pub fn redefine_first_value(&mut self, pos: &mut Cursor) -> Inst {
|
pub fn redefine_first_value(&mut self, pos: &mut Cursor) -> Inst {
|
||||||
let orig = pos.current_inst()
|
let orig = pos.current_inst()
|
||||||
.expect("Cursor must point at an instruction");
|
.expect("Cursor must point at an instruction");
|
||||||
|
let first_res = self.first_result(orig);
|
||||||
|
let first_type = self.value_type(first_res);
|
||||||
let data = self[orig].clone();
|
let data = self[orig].clone();
|
||||||
// After cloning, any secondary values are attached to both copies. Don't do that, we only
|
let results = self.results[orig].take();
|
||||||
// want them on the new clone.
|
self.results[orig].push(first_res, &mut self.value_lists);
|
||||||
let mut results = self.results[orig].take();
|
|
||||||
self.detach_secondary_results(orig);
|
|
||||||
let new = self.make_inst(data);
|
let new = self.make_inst(data);
|
||||||
results.as_mut_slice(&mut self.value_lists)[0] = Value::new_direct(new);
|
let new_first = self.make_value(ValueData::Inst {
|
||||||
self.results[new] = results;
|
ty: first_type,
|
||||||
|
num: 0,
|
||||||
|
inst: new,
|
||||||
|
next: None.into(),
|
||||||
|
});
|
||||||
|
self.results[new].push(new_first, &mut self.value_lists);
|
||||||
|
|
||||||
|
for i in 1.. {
|
||||||
|
if let Some(v) = results.get(i, &self.value_lists) {
|
||||||
|
self.attach_result(new, v);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pos.insert_inst(new);
|
pos.insert_inst(new);
|
||||||
// Replace the original instruction with a copy of the new value.
|
// Replace the original instruction with a copy of the new value.
|
||||||
// This is likely to be immediately overwritten by something else, but this way we avoid
|
// This is likely to be immediately overwritten by something else, but this way we avoid
|
||||||
// leaving the DFG in a state with multiple references to secondary results and value
|
// leaving the DFG in a state with multiple references to secondary results and value
|
||||||
// lists. It also means that this method doesn't change the semantics of the program.
|
// lists. It also means that this method doesn't change the semantics of the program.
|
||||||
let new_value = self.first_result(new);
|
self.replace(orig).copy(new_first);
|
||||||
self.replace(orig).copy(new_value);
|
|
||||||
new
|
new
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -898,7 +918,7 @@ mod tests {
|
|||||||
let inst = dfg.make_inst(idata);
|
let inst = dfg.make_inst(idata);
|
||||||
dfg.make_inst_results(inst, types::I32);
|
dfg.make_inst_results(inst, types::I32);
|
||||||
assert_eq!(inst.to_string(), "inst0");
|
assert_eq!(inst.to_string(), "inst0");
|
||||||
assert_eq!(dfg.display_inst(inst).to_string(), "v0 = iconst.i32");
|
assert_eq!(dfg.display_inst(inst).to_string(), "vx0 = iconst.i32");
|
||||||
|
|
||||||
// Immutable reference resolution.
|
// Immutable reference resolution.
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ fn legalize_inst_results<ResType>(dfg: &mut DataFlowGraph,
|
|||||||
-> Inst
|
-> Inst
|
||||||
where ResType: FnMut(&DataFlowGraph, usize) -> ArgumentType
|
where ResType: FnMut(&DataFlowGraph, usize) -> ArgumentType
|
||||||
{
|
{
|
||||||
let mut call = pos.current_inst()
|
let call = pos.current_inst()
|
||||||
.expect("Cursor must point to a call instruction");
|
.expect("Cursor must point to a call instruction");
|
||||||
|
|
||||||
// We theoretically allow for call instructions that return a number of fixed results before
|
// We theoretically allow for call instructions that return a number of fixed results before
|
||||||
@@ -115,58 +115,26 @@ fn legalize_inst_results<ResType>(dfg: &mut DataFlowGraph,
|
|||||||
let fixed_results = dfg[call].opcode().constraints().fixed_results();
|
let fixed_results = dfg[call].opcode().constraints().fixed_results();
|
||||||
assert_eq!(fixed_results, 0, "Fixed results on calls not supported");
|
assert_eq!(fixed_results, 0, "Fixed results on calls not supported");
|
||||||
|
|
||||||
let mut next_res = dfg.detach_secondary_results(call);
|
let results = dfg.detach_results(call);
|
||||||
// The currently last result on the call instruction.
|
let mut next_res = 0;
|
||||||
let mut last_res = dfg.first_result(call);
|
|
||||||
let mut abi_res = 0;
|
let mut abi_res = 0;
|
||||||
|
|
||||||
// The first result requires special handling.
|
// Point immediately after the call.
|
||||||
let first_ty = dfg.value_type(last_res);
|
|
||||||
if first_ty != get_abi_type(dfg, abi_res).value_type {
|
|
||||||
// Move the call out of the way, so we can redefine the first result.
|
|
||||||
let copy = call;
|
|
||||||
call = dfg.redefine_first_value(pos);
|
|
||||||
last_res = dfg.first_result(call);
|
|
||||||
// Set up a closure that can attach new results to `call`.
|
|
||||||
let mut get_res = |dfg: &mut DataFlowGraph, ty| {
|
|
||||||
let abi_type = get_abi_type(dfg, abi_res);
|
|
||||||
if ty == abi_type.value_type {
|
|
||||||
// Don't append the first result - it's not detachable.
|
|
||||||
if fixed_results + abi_res == 0 {
|
|
||||||
*dfg[call].first_type_mut() = ty;
|
|
||||||
debug_assert_eq!(last_res, dfg.first_result(call));
|
|
||||||
} else {
|
|
||||||
last_res = dfg.append_secondary_result(last_res, ty);
|
|
||||||
}
|
|
||||||
abi_res += 1;
|
|
||||||
Ok(last_res)
|
|
||||||
} else {
|
|
||||||
Err(abi_type)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let v = convert_from_abi(dfg, pos, first_ty, &mut get_res);
|
|
||||||
dfg.replace(copy).copy(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Point immediately after the call and any instructions dealing with the first result.
|
|
||||||
pos.next_inst();
|
pos.next_inst();
|
||||||
|
|
||||||
// Now do the secondary results.
|
while let Some(res) = results.get(next_res, &dfg.value_lists) {
|
||||||
while let Some(res) = next_res {
|
next_res += 1;
|
||||||
next_res = dfg.next_secondary_result(res);
|
|
||||||
|
|
||||||
let res_type = dfg.value_type(res);
|
let res_type = dfg.value_type(res);
|
||||||
if res_type == get_abi_type(dfg, abi_res).value_type {
|
if res_type == get_abi_type(dfg, abi_res).value_type {
|
||||||
// No value translation is necessary, this result matches the ABI type.
|
// No value translation is necessary, this result matches the ABI type.
|
||||||
dfg.attach_secondary_result(last_res, res);
|
dfg.attach_result(call, res);
|
||||||
last_res = res;
|
|
||||||
abi_res += 1;
|
abi_res += 1;
|
||||||
} else {
|
} else {
|
||||||
let mut get_res = |dfg: &mut DataFlowGraph, ty| {
|
let mut get_res = |dfg: &mut DataFlowGraph, ty| {
|
||||||
let abi_type = get_abi_type(dfg, abi_res);
|
let abi_type = get_abi_type(dfg, abi_res);
|
||||||
if ty == abi_type.value_type {
|
if ty == abi_type.value_type {
|
||||||
last_res = dfg.append_secondary_result(last_res, ty);
|
let last_res = dfg.append_result(call, ty);
|
||||||
abi_res += 1;
|
abi_res += 1;
|
||||||
Ok(last_res)
|
Ok(last_res)
|
||||||
} else {
|
} else {
|
||||||
@@ -199,13 +167,18 @@ fn convert_from_abi<GetArg>(dfg: &mut DataFlowGraph,
|
|||||||
{
|
{
|
||||||
// Terminate the recursion when we get the desired type.
|
// Terminate the recursion when we get the desired type.
|
||||||
let arg_type = match get_arg(dfg, ty) {
|
let arg_type = match get_arg(dfg, ty) {
|
||||||
Ok(v) => return v,
|
Ok(v) => {
|
||||||
|
debug_assert_eq!(dfg.value_type(v), ty);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
Err(t) => t,
|
Err(t) => t,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reconstruct how `ty` was legalized into the `arg_type` argument.
|
// Reconstruct how `ty` was legalized into the `arg_type` argument.
|
||||||
let conversion = legalize_abi_value(ty, &arg_type);
|
let conversion = legalize_abi_value(ty, &arg_type);
|
||||||
|
|
||||||
|
dbg!("convert_from_abi({}): {:?}", ty, conversion);
|
||||||
|
|
||||||
// The conversion describes value to ABI argument. We implement the reverse conversion here.
|
// The conversion describes value to ABI argument. We implement the reverse conversion here.
|
||||||
match conversion {
|
match conversion {
|
||||||
// Construct a `ty` by concatenating two ABI integers.
|
// Construct a `ty` by concatenating two ABI integers.
|
||||||
@@ -213,6 +186,11 @@ fn convert_from_abi<GetArg>(dfg: &mut DataFlowGraph,
|
|||||||
let abi_ty = ty.half_width().expect("Invalid type for conversion");
|
let abi_ty = ty.half_width().expect("Invalid type for conversion");
|
||||||
let lo = convert_from_abi(dfg, pos, abi_ty, get_arg);
|
let lo = convert_from_abi(dfg, pos, abi_ty, get_arg);
|
||||||
let hi = convert_from_abi(dfg, pos, abi_ty, get_arg);
|
let hi = convert_from_abi(dfg, pos, abi_ty, get_arg);
|
||||||
|
dbg!("intsplit {}: {}, {}: {}",
|
||||||
|
lo,
|
||||||
|
dfg.value_type(lo),
|
||||||
|
hi,
|
||||||
|
dfg.value_type(hi));
|
||||||
dfg.ins(pos).iconcat(lo, hi)
|
dfg.ins(pos).iconcat(lo, hi)
|
||||||
}
|
}
|
||||||
// Construct a `ty` by concatenating two halves of a vector.
|
// Construct a `ty` by concatenating two halves of a vector.
|
||||||
|
|||||||
@@ -1750,12 +1750,12 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(func.name.to_string(), "qux");
|
assert_eq!(func.name.to_string(), "qux");
|
||||||
let v4 = details.map.lookup_str("v4").unwrap();
|
let v4 = details.map.lookup_str("v4").unwrap();
|
||||||
assert_eq!(v4.to_string(), "v0");
|
assert_eq!(v4.to_string(), "vx0");
|
||||||
let vx3 = details.map.lookup_str("vx3").unwrap();
|
let vx3 = details.map.lookup_str("vx3").unwrap();
|
||||||
assert_eq!(vx3.to_string(), "vx0");
|
assert_eq!(vx3.to_string(), "vx2");
|
||||||
let aliased_to = func.dfg
|
let aliased_to = func.dfg
|
||||||
.resolve_aliases(Value::table_with_number(0).unwrap());
|
.resolve_aliases(Value::table_with_number(0).unwrap());
|
||||||
assert_eq!(aliased_to.to_string(), "v0");
|
assert_eq!(aliased_to.to_string(), "vx0");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -243,6 +243,6 @@ mod tests {
|
|||||||
assert_eq!(map.lookup_str("ebb0").unwrap().to_string(), "ebb0");
|
assert_eq!(map.lookup_str("ebb0").unwrap().to_string(), "ebb0");
|
||||||
assert_eq!(map.lookup_str("v4").unwrap().to_string(), "vx0");
|
assert_eq!(map.lookup_str("v4").unwrap().to_string(), "vx0");
|
||||||
assert_eq!(map.lookup_str("vx7").unwrap().to_string(), "vx1");
|
assert_eq!(map.lookup_str("vx7").unwrap().to_string(), "vx1");
|
||||||
assert_eq!(map.lookup_str("v10").unwrap().to_string(), "v0");
|
assert_eq!(map.lookup_str("v10").unwrap().to_string(), "vx2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user