diff --git a/filetests/isa/riscv/legalize-abi.cton b/filetests/isa/riscv/legalize-abi.cton index 2e7da079bf..06d68768bd 100644 --- a/filetests/isa/riscv/legalize-abi.cton +++ b/filetests/isa/riscv/legalize-abi.cton @@ -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): diff --git a/lib/cretonne/src/ir/dfg.rs b/lib/cretonne/src/ir/dfg.rs index 0b0ea7a8cc..359a6cd089 100644 --- a/lib/cretonne/src/ir/dfg.rs +++ b/lib/cretonne/src/ir/dfg.rs @@ -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. { diff --git a/lib/cretonne/src/legalizer/boundary.rs b/lib/cretonne/src/legalizer/boundary.rs index f80b6574c4..272a19dfee 100644 --- a/lib/cretonne/src/legalizer/boundary.rs +++ b/lib/cretonne/src/legalizer/boundary.rs @@ -107,7 +107,7 @@ fn legalize_inst_results(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(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(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(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. diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index f948b1f586..a501d6aaa3 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -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] diff --git a/lib/reader/src/sourcemap.rs b/lib/reader/src/sourcemap.rs index cbea4b02a2..7f387ccee2 100644 --- a/lib/reader/src/sourcemap.rs +++ b/lib/reader/src/sourcemap.rs @@ -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"); } }