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:
Jakob Stoklund Olesen
2017-04-12 11:02:59 -07:00
parent 06b52744db
commit b9808bedc4
5 changed files with 59 additions and 63 deletions

View File

@@ -34,9 +34,8 @@ ebb0:
; check: $ebb0:
; nextln: $(v1l=$V), $(v1h=$V) = call $fn1()
; check: $(v1new=$V) = iconcat $v1l, $v1h
; check: $v1 = copy $v1new
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)
ebb1(v10: i64):
@@ -77,9 +76,8 @@ ebb0:
; check: $ebb0:
; nextln: $(rv=$V) = call $fn1()
; check: $(v1new=$V) = ireduce.i8 $rv
; check: $v1 = copy $v1new
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)
ebb1(v10: i8):

View File

@@ -454,8 +454,14 @@ impl DataFlowGraph {
*self.insts[inst].first_type_mut() = first_type.unwrap_or_default();
// Include the first result in the results vector.
if first_type.is_some() {
self.results[inst].push(Value::new_direct(inst), &mut self.value_lists);
if let Some(ty) = first_type {
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]
.as_mut_slice(&mut self.value_lists)
@@ -489,11 +495,10 @@ impl DataFlowGraph {
return None;
}
let first = self.results[inst].first(&mut self.value_lists).unwrap();
let second = self.results[inst].get(1, &mut self.value_lists);
self.results[inst].clear(&mut self.value_lists);
if !self.insts[inst].first_type().is_void() {
self.results[inst].push(Value::new_direct(inst), &mut self.value_lists);
}
self.results[inst].push(first, &mut self.value_lists);
second
}
@@ -649,21 +654,36 @@ impl DataFlowGraph {
pub fn redefine_first_value(&mut self, pos: &mut Cursor) -> Inst {
let orig = pos.current_inst()
.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();
// After cloning, any secondary values are attached to both copies. Don't do that, we only
// want them on the new clone.
let mut results = self.results[orig].take();
self.detach_secondary_results(orig);
let results = self.results[orig].take();
self.results[orig].push(first_res, &mut self.value_lists);
let new = self.make_inst(data);
results.as_mut_slice(&mut self.value_lists)[0] = Value::new_direct(new);
self.results[new] = results;
let new_first = self.make_value(ValueData::Inst {
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);
// 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
// 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.
let new_value = self.first_result(new);
self.replace(orig).copy(new_value);
self.replace(orig).copy(new_first);
new
}
@@ -898,7 +918,7 @@ mod tests {
let inst = dfg.make_inst(idata);
dfg.make_inst_results(inst, types::I32);
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.
{

View File

@@ -107,7 +107,7 @@ fn legalize_inst_results<ResType>(dfg: &mut DataFlowGraph,
-> Inst
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");
// 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();
assert_eq!(fixed_results, 0, "Fixed results on calls not supported");
let mut next_res = dfg.detach_secondary_results(call);
// The currently last result on the call instruction.
let mut last_res = dfg.first_result(call);
let results = dfg.detach_results(call);
let mut next_res = 0;
let mut abi_res = 0;
// The first result requires special handling.
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.
// Point immediately after the call.
pos.next_inst();
// Now do the secondary results.
while let Some(res) = next_res {
next_res = dfg.next_secondary_result(res);
while let Some(res) = results.get(next_res, &dfg.value_lists) {
next_res += 1;
let res_type = dfg.value_type(res);
if res_type == get_abi_type(dfg, abi_res).value_type {
// No value translation is necessary, this result matches the ABI type.
dfg.attach_secondary_result(last_res, res);
last_res = res;
dfg.attach_result(call, res);
abi_res += 1;
} else {
let mut get_res = |dfg: &mut DataFlowGraph, ty| {
let abi_type = get_abi_type(dfg, abi_res);
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;
Ok(last_res)
} else {
@@ -199,13 +167,18 @@ fn convert_from_abi<GetArg>(dfg: &mut DataFlowGraph,
{
// Terminate the recursion when we get the desired type.
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,
};
// Reconstruct how `ty` was legalized into the `arg_type` argument.
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.
match conversion {
// 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 lo = 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)
}
// Construct a `ty` by concatenating two halves of a vector.

View File

@@ -1750,12 +1750,12 @@ mod tests {
.unwrap();
assert_eq!(func.name.to_string(), "qux");
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();
assert_eq!(vx3.to_string(), "vx0");
assert_eq!(vx3.to_string(), "vx2");
let aliased_to = func.dfg
.resolve_aliases(Value::table_with_number(0).unwrap());
assert_eq!(aliased_to.to_string(), "v0");
assert_eq!(aliased_to.to_string(), "vx0");
}
#[test]

View File

@@ -243,6 +243,6 @@ mod tests {
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("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");
}
}