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: ; 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):

View File

@@ -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.
{ {

View File

@@ -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.

View File

@@ -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]

View File

@@ -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");
} }
} }