Eliminate layout::Cursor from cton_frontend.

Replace all uses with a FuncCursor.

Avoid the anti-pattern of passing parts of a function around as
independent references.
This commit is contained in:
Jakob Stoklund Olesen
2017-09-21 12:16:32 -07:00
parent 03dee5e442
commit 1cd91b6f30
4 changed files with 172 additions and 485 deletions

View File

@@ -223,7 +223,8 @@ impl LoopAnalysis {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use ir::{Function, InstBuilder, Cursor, CursorBase, types}; use cursor::{Cursor, FuncCursor};
use ir::{Function, InstBuilder, types};
use loop_analysis::{Loop, LoopAnalysis}; use loop_analysis::{Loop, LoopAnalysis};
use flowgraph::ControlFlowGraph; use flowgraph::ControlFlowGraph;
use dominator_tree::DominatorTree; use dominator_tree::DominatorTree;
@@ -238,21 +239,20 @@ mod test {
let cond = func.dfg.append_ebb_arg(ebb0, types::I32); let cond = func.dfg.append_ebb_arg(ebb0, types::I32);
{ {
let dfg = &mut func.dfg; let mut cur = FuncCursor::new(&mut func);
let cur = &mut Cursor::new(&mut func.layout);
cur.insert_ebb(ebb0); cur.insert_ebb(ebb0);
dfg.ins(cur).jump(ebb1, &[]); cur.ins().jump(ebb1, &[]);
cur.insert_ebb(ebb1); cur.insert_ebb(ebb1);
dfg.ins(cur).jump(ebb2, &[]); cur.ins().jump(ebb2, &[]);
cur.insert_ebb(ebb2); cur.insert_ebb(ebb2);
dfg.ins(cur).brnz(cond, ebb1, &[]); cur.ins().brnz(cond, ebb1, &[]);
dfg.ins(cur).jump(ebb3, &[]); cur.ins().jump(ebb3, &[]);
cur.insert_ebb(ebb3); cur.insert_ebb(ebb3);
dfg.ins(cur).brnz(cond, ebb0, &[]); cur.ins().brnz(cond, ebb0, &[]);
} }
@@ -291,29 +291,28 @@ mod test {
let cond = func.dfg.append_ebb_arg(ebb0, types::I32); let cond = func.dfg.append_ebb_arg(ebb0, types::I32);
{ {
let dfg = &mut func.dfg; let mut cur = FuncCursor::new(&mut func);
let cur = &mut Cursor::new(&mut func.layout);
cur.insert_ebb(ebb0); cur.insert_ebb(ebb0);
dfg.ins(cur).brnz(cond, ebb1, &[]); cur.ins().brnz(cond, ebb1, &[]);
dfg.ins(cur).jump(ebb3, &[]); cur.ins().jump(ebb3, &[]);
cur.insert_ebb(ebb1); cur.insert_ebb(ebb1);
dfg.ins(cur).jump(ebb2, &[]); cur.ins().jump(ebb2, &[]);
cur.insert_ebb(ebb2); cur.insert_ebb(ebb2);
dfg.ins(cur).brnz(cond, ebb1, &[]); cur.ins().brnz(cond, ebb1, &[]);
dfg.ins(cur).jump(ebb5, &[]); cur.ins().jump(ebb5, &[]);
cur.insert_ebb(ebb3); cur.insert_ebb(ebb3);
dfg.ins(cur).jump(ebb4, &[]); cur.ins().jump(ebb4, &[]);
cur.insert_ebb(ebb4); cur.insert_ebb(ebb4);
dfg.ins(cur).brnz(cond, ebb3, &[]); cur.ins().brnz(cond, ebb3, &[]);
dfg.ins(cur).jump(ebb5, &[]); cur.ins().jump(ebb5, &[]);
cur.insert_ebb(ebb5); cur.insert_ebb(ebb5);
dfg.ins(cur).brnz(cond, ebb0, &[]); cur.ins().brnz(cond, ebb0, &[]);
} }

View File

@@ -80,9 +80,10 @@ impl TopoOrder {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use cursor::{Cursor, FuncCursor};
use flowgraph::ControlFlowGraph; use flowgraph::ControlFlowGraph;
use dominator_tree::DominatorTree; use dominator_tree::DominatorTree;
use ir::{Function, InstBuilder, Cursor, CursorBase}; use ir::{Function, InstBuilder};
use std::iter; use std::iter;
use super::*; use super::*;
@@ -105,13 +106,12 @@ mod test {
let ebb1 = func.dfg.make_ebb(); let ebb1 = func.dfg.make_ebb();
{ {
let dfg = &mut func.dfg; let mut cur = FuncCursor::new(&mut func);
let cur = &mut Cursor::new(&mut func.layout);
cur.insert_ebb(ebb0); cur.insert_ebb(ebb0);
dfg.ins(cur).jump(ebb1, &[]); cur.ins().jump(ebb1, &[]);
cur.insert_ebb(ebb1); cur.insert_ebb(ebb1);
dfg.ins(cur).jump(ebb1, &[]); cur.ins().jump(ebb1, &[]);
} }
let cfg = ControlFlowGraph::with_function(&func); let cfg = ControlFlowGraph::with_function(&func);

View File

@@ -271,12 +271,7 @@ where
/// created. Forgetting to call this method on every block will cause inconsistences in the /// created. Forgetting to call this method on every block will cause inconsistences in the
/// produced functions. /// produced functions.
pub fn seal_block(&mut self, ebb: Ebb) { pub fn seal_block(&mut self, ebb: Ebb) {
let side_effects = self.builder.ssa.seal_ebb_header_block( let side_effects = self.builder.ssa.seal_ebb_header_block(ebb, self.func);
ebb,
&mut self.func.dfg,
&mut self.func.layout,
&mut self.func.jump_tables,
);
self.handle_ssa_side_effects(side_effects); self.handle_ssa_side_effects(side_effects);
} }
@@ -292,9 +287,7 @@ where
"this variable is used but its type has not been declared", "this variable is used but its type has not been declared",
); );
let (val, side_effects) = self.builder.ssa.use_var( let (val, side_effects) = self.builder.ssa.use_var(
&mut self.func.dfg, self.func,
&mut self.func.layout,
&mut self.func.jump_tables,
var, var,
ty, ty,
self.position.basic_block, self.position.basic_block,

View File

@@ -5,8 +5,8 @@
//! In: Jhala R., De Bosschere K. (eds) Compiler Construction. CC 2013. //! In: Jhala R., De Bosschere K. (eds) Compiler Construction. CC 2013.
//! Lecture Notes in Computer Science, vol 7791. Springer, Berlin, Heidelberg //! Lecture Notes in Computer Science, vol 7791. Springer, Berlin, Heidelberg
use cretonne::ir::{Ebb, Value, Inst, Type, DataFlowGraph, JumpTables, Layout, Cursor, CursorBase, use cretonne::cursor::{Cursor, FuncCursor};
InstBuilder}; use cretonne::ir::{Ebb, Value, Inst, Type, Function, InstBuilder};
use cretonne::ir::instructions::BranchInfo; use cretonne::ir::instructions::BranchInfo;
use cretonne::entity::{EntityRef, PrimaryMap, EntityMap}; use cretonne::entity::{EntityRef, PrimaryMap, EntityMap};
use cretonne::packed_option::PackedOption; use cretonne::packed_option::PackedOption;
@@ -217,9 +217,7 @@ where
/// responsible for making sure that you initialize your variables. /// responsible for making sure that you initialize your variables.
pub fn use_var( pub fn use_var(
&mut self, &mut self,
dfg: &mut DataFlowGraph, func: &mut Function,
layout: &mut Layout,
jts: &mut JumpTables,
var: Variable, var: Variable,
ty: Type, ty: Type,
block: Block, block: Block,
@@ -232,16 +230,14 @@ where
} }
// Otherwise, we have to do a non-local lookup. // Otherwise, we have to do a non-local lookup.
self.use_var_nonlocal(dfg, layout, jts, var, ty, block) self.use_var_nonlocal(func, var, ty, block)
} }
// The non-local case of use_var. Query each predecessor for a value and add branch // The non-local case of use_var. Query each predecessor for a value and add branch
// arguments as needed to satisfy the use. // arguments as needed to satisfy the use.
fn use_var_nonlocal( fn use_var_nonlocal(
&mut self, &mut self,
dfg: &mut DataFlowGraph, func: &mut Function,
layout: &mut Layout,
jts: &mut JumpTables,
var: Variable, var: Variable,
ty: Type, ty: Type,
block: Block, block: Block,
@@ -255,11 +251,11 @@ where
// Only one predecessor, straightforward case // Only one predecessor, straightforward case
UseVarCases::SealedOnePredecessor(data.predecessors[0].0) UseVarCases::SealedOnePredecessor(data.predecessors[0].0)
} else { } else {
let val = dfg.append_ebb_arg(data.ebb, ty); let val = func.dfg.append_ebb_arg(data.ebb, ty);
UseVarCases::SealedMultiplePredecessors(val, data.ebb) UseVarCases::SealedMultiplePredecessors(val, data.ebb)
} }
} else { } else {
let val = dfg.append_ebb_arg(data.ebb, ty); let val = func.dfg.append_ebb_arg(data.ebb, ty);
data.undef_variables.push((var, val)); data.undef_variables.push((var, val));
UseVarCases::Unsealed(val) UseVarCases::Unsealed(val)
} }
@@ -271,7 +267,7 @@ where
// The block has a single predecessor or multiple predecessor with // The block has a single predecessor or multiple predecessor with
// the same value, we look into it. // the same value, we look into it.
UseVarCases::SealedOnePredecessor(pred) => { UseVarCases::SealedOnePredecessor(pred) => {
let (val, mids) = self.use_var(dfg, layout, jts, var, ty, pred); let (val, mids) = self.use_var(func, var, ty, pred);
self.def_var(var, val, block); self.def_var(var, val, block);
(val, mids) (val, mids)
} }
@@ -285,7 +281,7 @@ where
// If multiple predecessor we look up a use_var in each of them: // If multiple predecessor we look up a use_var in each of them:
// if they all yield the same value no need for an Ebb argument // if they all yield the same value no need for an Ebb argument
self.def_var(var, val, block); self.def_var(var, val, block);
self.predecessors_lookup(dfg, layout, jts, val, var, ebb) self.predecessors_lookup(func, val, var, ebb)
} }
} }
} }
@@ -354,13 +350,7 @@ where
/// take into account the Phi function placed by the SSA algorithm. /// take into account the Phi function placed by the SSA algorithm.
/// ///
/// Returns the list of newly created ebbs for critical edge splitting. /// Returns the list of newly created ebbs for critical edge splitting.
pub fn seal_ebb_header_block( pub fn seal_ebb_header_block(&mut self, ebb: Ebb, func: &mut Function) -> SideEffects {
&mut self,
ebb: Ebb,
dfg: &mut DataFlowGraph,
layout: &mut Layout,
jts: &mut JumpTables,
) -> SideEffects {
let block = self.header_block(ebb); let block = self.header_block(ebb);
let (undef_vars, ebb): (Vec<(Variable, Value)>, Ebb) = match self.blocks[block] { let (undef_vars, ebb): (Vec<(Variable, Value)>, Ebb) = match self.blocks[block] {
@@ -378,7 +368,7 @@ where
// For each undef var we look up values in the predecessors and create an Ebb argument // For each undef var we look up values in the predecessors and create an Ebb argument
// only if necessary. // only if necessary.
for (var, val) in undef_vars { for (var, val) in undef_vars {
let (_, local_side_effects) = self.predecessors_lookup(dfg, layout, jts, val, var, ebb); let (_, local_side_effects) = self.predecessors_lookup(func, val, var, ebb);
side_effects.append(local_side_effects); side_effects.append(local_side_effects);
} }
@@ -399,15 +389,13 @@ where
/// list of Ebb that are the middle of newly created critical edges splits. /// list of Ebb that are the middle of newly created critical edges splits.
fn predecessors_lookup( fn predecessors_lookup(
&mut self, &mut self,
dfg: &mut DataFlowGraph, func: &mut Function,
layout: &mut Layout,
jts: &mut JumpTables,
temp_arg_val: Value, temp_arg_val: Value,
temp_arg_var: Variable, temp_arg_var: Variable,
dest_ebb: Ebb, dest_ebb: Ebb,
) -> (Value, SideEffects) { ) -> (Value, SideEffects) {
let mut pred_values: ZeroOneOrMore<Value> = ZeroOneOrMore::Zero(); let mut pred_values: ZeroOneOrMore<Value> = ZeroOneOrMore::Zero();
let ty = dfg.value_type(temp_arg_val); let ty = func.dfg.value_type(temp_arg_val);
let mut side_effects = SideEffects::new(); let mut side_effects = SideEffects::new();
// Iterate over the predecessors. To avoid borrowing `self` for the whole loop, // Iterate over the predecessors. To avoid borrowing `self` for the whole loop,
@@ -417,8 +405,7 @@ where
for &(pred, _) in &preds { for &(pred, _) in &preds {
// For each predecessor, we query what is the local SSA value corresponding // For each predecessor, we query what is the local SSA value corresponding
// to var and we put it as an argument of the branch instruction. // to var and we put it as an argument of the branch instruction.
let (pred_val, local_side_effects) = let (pred_val, local_side_effects) = self.use_var(func, temp_arg_var, ty, pred);
self.use_var(dfg, layout, jts, temp_arg_var, ty, pred);
match pred_values { match pred_values {
ZeroOneOrMore::Zero() => { ZeroOneOrMore::Zero() => {
if pred_val != temp_arg_val { if pred_val != temp_arg_val {
@@ -441,17 +428,17 @@ where
// The variable is used but never defined before. This is an irregularity in the // The variable is used but never defined before. This is an irregularity in the
// code, but rather than throwing an error we silently initialize the variable to // code, but rather than throwing an error we silently initialize the variable to
// 0. This will have no effect since this situation happens in unreachable code. // 0. This will have no effect since this situation happens in unreachable code.
if !layout.is_ebb_inserted(dest_ebb) { if !func.layout.is_ebb_inserted(dest_ebb) {
layout.append_ebb(dest_ebb) func.layout.append_ebb(dest_ebb)
}; };
let mut cur = Cursor::new(layout).at_first_insertion_point(dest_ebb); let ty = func.dfg.value_type(temp_arg_val);
let ty = dfg.value_type(temp_arg_val); let mut cur = FuncCursor::new(func).at_first_insertion_point(dest_ebb);
let val = if ty.is_int() { let val = if ty.is_int() {
dfg.ins(&mut cur).iconst(ty, 0) cur.ins().iconst(ty, 0)
} else if ty == F32 { } else if ty == F32 {
dfg.ins(&mut cur).f32const(Ieee32::with_bits(0)) cur.ins().f32const(Ieee32::with_bits(0))
} else if ty == F64 { } else if ty == F64 {
dfg.ins(&mut cur).f64const(Ieee64::with_bits(0)) cur.ins().f64const(Ieee64::with_bits(0))
} else { } else {
panic!("value used but never declared and initialization not supported") panic!("value used but never declared and initialization not supported")
}; };
@@ -463,8 +450,8 @@ where
// so we don't need to have it as an ebb argument. // so we don't need to have it as an ebb argument.
// We need to replace all the occurences of val with pred_val but since // We need to replace all the occurences of val with pred_val but since
// we can't afford a re-writing pass right now we just declare an alias. // we can't afford a re-writing pass right now we just declare an alias.
dfg.remove_ebb_arg(temp_arg_val); func.dfg.remove_ebb_arg(temp_arg_val);
dfg.change_to_alias(temp_arg_val, pred_val); func.dfg.change_to_alias(temp_arg_val, pred_val);
pred_val pred_val
} }
ZeroOneOrMore::More() => { ZeroOneOrMore::More() => {
@@ -480,14 +467,12 @@ where
.unwrap(); .unwrap();
if let Some((middle_ebb, middle_block, middle_jump_inst)) = if let Some((middle_ebb, middle_block, middle_jump_inst)) =
self.append_jump_argument( self.append_jump_argument(
dfg, func,
layout,
*last_inst, *last_inst,
*pred_block, *pred_block,
dest_ebb, dest_ebb,
pred_val, pred_val,
temp_arg_var, temp_arg_var,
jts,
) )
{ {
*pred_block = middle_block; *pred_block = middle_block;
@@ -511,41 +496,39 @@ where
/// critical edge splitting. /// critical edge splitting.
fn append_jump_argument( fn append_jump_argument(
&mut self, &mut self,
dfg: &mut DataFlowGraph, func: &mut Function,
layout: &mut Layout,
jump_inst: Inst, jump_inst: Inst,
jump_inst_block: Block, jump_inst_block: Block,
dest_ebb: Ebb, dest_ebb: Ebb,
val: Value, val: Value,
var: Variable, var: Variable,
jts: &mut JumpTables,
) -> Option<(Ebb, Block, Inst)> { ) -> Option<(Ebb, Block, Inst)> {
match dfg[jump_inst].analyze_branch(&dfg.value_lists) { match func.dfg[jump_inst].analyze_branch(&func.dfg.value_lists) {
BranchInfo::NotABranch => { BranchInfo::NotABranch => {
panic!("you have declared a non-branch instruction as a predecessor to an ebb"); panic!("you have declared a non-branch instruction as a predecessor to an ebb");
} }
// For a single destination appending a jump argument to the instruction // For a single destination appending a jump argument to the instruction
// is sufficient. // is sufficient.
BranchInfo::SingleDest(_, _) => { BranchInfo::SingleDest(_, _) => {
dfg.append_inst_arg(jump_inst, val); func.dfg.append_inst_arg(jump_inst, val);
None None
} }
BranchInfo::Table(jt) => { BranchInfo::Table(jt) => {
// In the case of a jump table, the situation is tricky because br_table doesn't // In the case of a jump table, the situation is tricky because br_table doesn't
// support arguments. // support arguments.
// We have to split the critical edge // We have to split the critical edge
let middle_ebb = dfg.make_ebb(); let middle_ebb = func.dfg.make_ebb();
layout.append_ebb(middle_ebb); func.layout.append_ebb(middle_ebb);
let block = self.declare_ebb_header_block(middle_ebb); let block = self.declare_ebb_header_block(middle_ebb);
self.blocks[block].add_predecessor(jump_inst_block, jump_inst); self.blocks[block].add_predecessor(jump_inst_block, jump_inst);
self.seal_ebb_header_block(middle_ebb, dfg, layout, jts); self.seal_ebb_header_block(middle_ebb, func);
for old_dest in jts[jt].as_mut_slice() { for old_dest in func.jump_tables[jt].as_mut_slice() {
if old_dest.unwrap() == dest_ebb { if old_dest.unwrap() == dest_ebb {
*old_dest = PackedOption::from(middle_ebb); *old_dest = PackedOption::from(middle_ebb);
} }
} }
let mut cur = Cursor::new(layout).at_bottom(middle_ebb); let mut cur = FuncCursor::new(func).at_bottom(middle_ebb);
let middle_jump_inst = dfg.ins(&mut cur).jump(dest_ebb, &[val]); let middle_jump_inst = cur.ins().jump(dest_ebb, &[val]);
self.def_var(var, val, block); self.def_var(var, val, block);
Some((middle_ebb, block, middle_jump_inst)) Some((middle_ebb, block, middle_jump_inst))
} }
@@ -581,8 +564,9 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use cretonne::cursor::{Cursor, FuncCursor};
use cretonne::entity::EntityRef; use cretonne::entity::EntityRef;
use cretonne::ir::{Function, InstBuilder, Cursor, CursorBase, Inst, JumpTableData}; use cretonne::ir::{Function, InstBuilder, Inst, JumpTableData};
use cretonne::ir::types::*; use cretonne::ir::types::*;
use cretonne::verify_function; use cretonne::verify_function;
use cretonne::ir::instructions::BranchInfo; use cretonne::ir::instructions::BranchInfo;
@@ -623,105 +607,37 @@ mod tests {
let block = ssa.declare_ebb_header_block(ebb0); let block = ssa.declare_ebb_header_block(ebb0);
let x_var = Variable(0); let x_var = Variable(0);
let x_ssa = { let x_ssa = {
let cur = &mut Cursor::new(&mut func.layout); let mut cur = FuncCursor::new(&mut func);
cur.insert_ebb(ebb0); cur.insert_ebb(ebb0);
func.dfg.ins(cur).iconst(I32, 1) cur.ins().iconst(I32, 1)
}; };
ssa.def_var(x_var, x_ssa, block); ssa.def_var(x_var, x_ssa, block);
let y_var = Variable(1); let y_var = Variable(1);
let y_ssa = { let y_ssa = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).iconst(I32, 2) cur.ins().iconst(I32, 2)
}; };
ssa.def_var(y_var, y_ssa, block); ssa.def_var(y_var, y_ssa, block);
assert_eq!( assert_eq!(ssa.use_var(&mut func, x_var, I32, block).0, x_ssa);
ssa.use_var( assert_eq!(ssa.use_var(&mut func, y_var, I32, block).0, y_ssa);
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block,
).0,
x_ssa
);
assert_eq!(
ssa.use_var(
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block,
).0,
y_ssa
);
let z_var = Variable(2); let z_var = Variable(2);
let x_use1 = ssa.use_var( let x_use1 = ssa.use_var(&mut func, x_var, I32, block).0;
&mut func.dfg, let y_use1 = ssa.use_var(&mut func, y_var, I32, block).0;
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block,
).0;
let y_use1 = ssa.use_var(
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block,
).0;
let z1_ssa = { let z1_ssa = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).iadd(x_use1, y_use1) cur.ins().iadd(x_use1, y_use1)
}; };
ssa.def_var(z_var, z1_ssa, block); ssa.def_var(z_var, z1_ssa, block);
assert_eq!( assert_eq!(ssa.use_var(&mut func, z_var, I32, block).0, z1_ssa);
ssa.use_var( let x_use2 = ssa.use_var(&mut func, x_var, I32, block).0;
&mut func.dfg, let z_use1 = ssa.use_var(&mut func, z_var, I32, block).0;
&mut func.layout,
&mut func.jump_tables,
z_var,
I32,
block,
).0,
z1_ssa
);
let x_use2 = ssa.use_var(
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block,
).0;
let z_use1 = ssa.use_var(
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
z_var,
I32,
block,
).0;
let z2_ssa = { let z2_ssa = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).iadd(x_use2, z_use1) cur.ins().iadd(x_use2, z_use1)
}; };
ssa.def_var(z_var, z2_ssa, block); ssa.def_var(z_var, z2_ssa, block);
assert_eq!( assert_eq!(ssa.use_var(&mut func, z_var, I32, block).0, z2_ssa);
ssa.use_var(
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
z_var,
I32,
block,
).0,
z2_ssa
);
} }
#[test] #[test]
@@ -743,146 +659,57 @@ mod tests {
let block0 = ssa.declare_ebb_header_block(ebb0); let block0 = ssa.declare_ebb_header_block(ebb0);
let x_var = Variable(0); let x_var = Variable(0);
let x_ssa = { let x_ssa = {
let cur = &mut Cursor::new(&mut func.layout); let mut cur = FuncCursor::new(&mut func);
cur.insert_ebb(ebb0); cur.insert_ebb(ebb0);
cur.insert_ebb(ebb1); cur.insert_ebb(ebb1);
cur.goto_bottom(ebb0); cur.goto_bottom(ebb0);
func.dfg.ins(cur).iconst(I32, 1) cur.ins().iconst(I32, 1)
}; };
ssa.def_var(x_var, x_ssa, block0); ssa.def_var(x_var, x_ssa, block0);
let y_var = Variable(1); let y_var = Variable(1);
let y_ssa = { let y_ssa = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).iconst(I32, 2) cur.ins().iconst(I32, 2)
}; };
ssa.def_var(y_var, y_ssa, block0); ssa.def_var(y_var, y_ssa, block0);
assert_eq!( assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x_ssa);
ssa.use_var( assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y_ssa);
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block0,
).0,
x_ssa
);
assert_eq!(
ssa.use_var(
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block0,
).0,
y_ssa
);
let z_var = Variable(2); let z_var = Variable(2);
let x_use1 = ssa.use_var( let x_use1 = ssa.use_var(&mut func, x_var, I32, block0).0;
&mut func.dfg, let y_use1 = ssa.use_var(&mut func, y_var, I32, block0).0;
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block0,
).0;
let y_use1 = ssa.use_var(
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block0,
).0;
let z1_ssa = { let z1_ssa = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).iadd(x_use1, y_use1) cur.ins().iadd(x_use1, y_use1)
}; };
ssa.def_var(z_var, z1_ssa, block0); ssa.def_var(z_var, z1_ssa, block0);
assert_eq!( assert_eq!(ssa.use_var(&mut func, z_var, I32, block0).0, z1_ssa);
ssa.use_var( let y_use2 = ssa.use_var(&mut func, y_var, I32, block0).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
z_var,
I32,
block0,
).0,
z1_ssa
);
let y_use2 = ssa.use_var(
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block0,
).0;
let jump_inst: Inst = { let jump_inst: Inst = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).brnz(y_use2, ebb1, &[]) cur.ins().brnz(y_use2, ebb1, &[])
}; };
let block1 = ssa.declare_ebb_body_block(block0); let block1 = ssa.declare_ebb_body_block(block0);
let x_use2 = ssa.use_var( let x_use2 = ssa.use_var(&mut func, x_var, I32, block1).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block1,
).0;
assert_eq!(x_use2, x_ssa); assert_eq!(x_use2, x_ssa);
let z_use1 = ssa.use_var( let z_use1 = ssa.use_var(&mut func, z_var, I32, block1).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
z_var,
I32,
block1,
).0;
assert_eq!(z_use1, z1_ssa); assert_eq!(z_use1, z1_ssa);
let z2_ssa = { let z2_ssa = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).iadd(x_use2, z_use1) cur.ins().iadd(x_use2, z_use1)
}; };
ssa.def_var(z_var, z2_ssa, block1); ssa.def_var(z_var, z2_ssa, block1);
assert_eq!( assert_eq!(ssa.use_var(&mut func, z_var, I32, block1).0, z2_ssa);
ssa.use_var( ssa.seal_ebb_header_block(ebb0, &mut func);
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
z_var,
I32,
block1,
).0,
z2_ssa
);
ssa.seal_ebb_header_block(ebb0, &mut func.dfg, &mut func.layout, &mut func.jump_tables);
let block2 = ssa.declare_ebb_header_block(ebb1); let block2 = ssa.declare_ebb_header_block(ebb1);
ssa.declare_ebb_predecessor(ebb1, block0, jump_inst); ssa.declare_ebb_predecessor(ebb1, block0, jump_inst);
ssa.seal_ebb_header_block(ebb1, &mut func.dfg, &mut func.layout, &mut func.jump_tables); ssa.seal_ebb_header_block(ebb1, &mut func);
let x_use3 = ssa.use_var( let x_use3 = ssa.use_var(&mut func, x_var, I32, block2).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block2,
).0;
assert_eq!(x_ssa, x_use3); assert_eq!(x_ssa, x_use3);
let y_use3 = ssa.use_var( let y_use3 = ssa.use_var(&mut func, y_var, I32, block2).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block2,
).0;
assert_eq!(y_ssa, y_use3); assert_eq!(y_ssa, y_use3);
let y2_ssa = { let y2_ssa = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb1); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).iadd(x_use3, y_use3) cur.ins().iadd(x_use3, y_use3)
}; };
ssa.def_var(y_var, y2_ssa, block2); ssa.def_var(y_var, y2_ssa, block2);
match func.dfg[jump_inst].analyze_branch(&func.dfg.value_lists) { match func.dfg[jump_inst].analyze_branch(&func.dfg.value_lists) {
@@ -917,179 +744,89 @@ mod tests {
// jump ebb1 // jump ebb1
let block0 = ssa.declare_ebb_header_block(ebb0); let block0 = ssa.declare_ebb_header_block(ebb0);
ssa.seal_ebb_header_block(ebb0, &mut func.dfg, &mut func.layout, &mut func.jump_tables); ssa.seal_ebb_header_block(ebb0, &mut func);
let x_var = Variable(0); let x_var = Variable(0);
let x1 = { let x1 = {
let cur = &mut Cursor::new(&mut func.layout); let mut cur = FuncCursor::new(&mut func);
cur.insert_ebb(ebb0); cur.insert_ebb(ebb0);
cur.insert_ebb(ebb1); cur.insert_ebb(ebb1);
cur.insert_ebb(ebb2); cur.insert_ebb(ebb2);
cur.goto_bottom(ebb0); cur.goto_bottom(ebb0);
func.dfg.ins(cur).iconst(I32, 1) cur.ins().iconst(I32, 1)
}; };
ssa.def_var(x_var, x1, block0); ssa.def_var(x_var, x1, block0);
assert_eq!( assert_eq!(ssa.use_var(&mut func, x_var, I32, block0).0, x1);
ssa.use_var(
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block0,
).0,
x1
);
let y_var = Variable(1); let y_var = Variable(1);
let y1 = { let y1 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).iconst(I32, 2) cur.ins().iconst(I32, 2)
}; };
ssa.def_var(y_var, y1, block0); ssa.def_var(y_var, y1, block0);
assert_eq!( assert_eq!(ssa.use_var(&mut func, y_var, I32, block0).0, y1);
ssa.use_var(
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block0,
).0,
y1
);
let z_var = Variable(2); let z_var = Variable(2);
let x2 = ssa.use_var( let x2 = ssa.use_var(&mut func, x_var, I32, block0).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block0,
).0;
assert_eq!(x2, x1); assert_eq!(x2, x1);
let y2 = ssa.use_var( let y2 = ssa.use_var(&mut func, y_var, I32, block0).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block0,
).0;
assert_eq!(y2, y1); assert_eq!(y2, y1);
let z1 = { let z1 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).iadd(x2, y2) cur.ins().iadd(x2, y2)
}; };
ssa.def_var(z_var, z1, block0); ssa.def_var(z_var, z1, block0);
let jump_ebb0_ebb1 = { let jump_ebb0_ebb1 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).jump(ebb1, &[]) cur.ins().jump(ebb1, &[])
}; };
let block1 = ssa.declare_ebb_header_block(ebb1); let block1 = ssa.declare_ebb_header_block(ebb1);
ssa.declare_ebb_predecessor(ebb1, block0, jump_ebb0_ebb1); ssa.declare_ebb_predecessor(ebb1, block0, jump_ebb0_ebb1);
let z2 = ssa.use_var( let z2 = ssa.use_var(&mut func, z_var, I32, block1).0;
&mut func.dfg, let y3 = ssa.use_var(&mut func, y_var, I32, block1).0;
&mut func.layout,
&mut func.jump_tables,
z_var,
I32,
block1,
).0;
let y3 = ssa.use_var(
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block1,
).0;
let z3 = { let z3 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb1); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
func.dfg.ins(cur).iadd(z2, y3) cur.ins().iadd(z2, y3)
}; };
ssa.def_var(z_var, z3, block1); ssa.def_var(z_var, z3, block1);
let y4 = ssa.use_var( let y4 = ssa.use_var(&mut func, y_var, I32, block1).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block1,
).0;
assert_eq!(y4, y3); assert_eq!(y4, y3);
let jump_ebb1_ebb2 = { let jump_ebb1_ebb2 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb1); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
func.dfg.ins(cur).brnz(y4, ebb2, &[]) cur.ins().brnz(y4, ebb2, &[])
}; };
let block2 = ssa.declare_ebb_body_block(block1); let block2 = ssa.declare_ebb_body_block(block1);
let z4 = ssa.use_var( let z4 = ssa.use_var(&mut func, z_var, I32, block2).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
z_var,
I32,
block2,
).0;
assert_eq!(z4, z3); assert_eq!(z4, z3);
let x3 = ssa.use_var( let x3 = ssa.use_var(&mut func, x_var, I32, block2).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block2,
).0;
let z5 = { let z5 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb1); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
func.dfg.ins(cur).isub(z4, x3) cur.ins().isub(z4, x3)
}; };
ssa.def_var(z_var, z5, block2); ssa.def_var(z_var, z5, block2);
let y5 = ssa.use_var( let y5 = ssa.use_var(&mut func, y_var, I32, block2).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block2,
).0;
assert_eq!(y5, y3); assert_eq!(y5, y3);
{ {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb1); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
func.dfg.ins(cur).return_(&[y5]) cur.ins().return_(&[y5])
}; };
let block3 = ssa.declare_ebb_header_block(ebb2); let block3 = ssa.declare_ebb_header_block(ebb2);
ssa.declare_ebb_predecessor(ebb2, block1, jump_ebb1_ebb2); ssa.declare_ebb_predecessor(ebb2, block1, jump_ebb1_ebb2);
ssa.seal_ebb_header_block(ebb2, &mut func.dfg, &mut func.layout, &mut func.jump_tables); ssa.seal_ebb_header_block(ebb2, &mut func);
let y6 = ssa.use_var( let y6 = ssa.use_var(&mut func, y_var, I32, block3).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block3,
).0;
assert_eq!(y6, y3); assert_eq!(y6, y3);
let x4 = ssa.use_var( let x4 = ssa.use_var(&mut func, x_var, I32, block3).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block3,
).0;
assert_eq!(x4, x3); assert_eq!(x4, x3);
let y7 = { let y7 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb2); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb2);
func.dfg.ins(cur).isub(y6, x4) cur.ins().isub(y6, x4)
}; };
ssa.def_var(y_var, y7, block3); ssa.def_var(y_var, y7, block3);
let jump_ebb2_ebb1 = { let jump_ebb2_ebb1 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb2); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb2);
func.dfg.ins(cur).jump(ebb1, &[]) cur.ins().jump(ebb1, &[])
}; };
ssa.declare_ebb_predecessor(ebb1, block3, jump_ebb2_ebb1); ssa.declare_ebb_predecessor(ebb1, block3, jump_ebb2_ebb1);
ssa.seal_ebb_header_block(ebb1, &mut func.dfg, &mut func.layout, &mut func.jump_tables); ssa.seal_ebb_header_block(ebb1, &mut func);
assert_eq!(func.dfg.ebb_args(ebb1)[0], z2); assert_eq!(func.dfg.ebb_args(ebb1)[0], z2);
assert_eq!(func.dfg.ebb_args(ebb1)[1], y3); assert_eq!(func.dfg.ebb_args(ebb1)[1], y3);
assert_eq!(func.dfg.resolve_aliases(x3), x1); assert_eq!(func.dfg.resolve_aliases(x3), x1);
@@ -1114,60 +851,46 @@ mod tests {
// return // return
// //
let block0 = ssa.declare_ebb_header_block(ebb0); let block0 = ssa.declare_ebb_header_block(ebb0);
ssa.seal_ebb_header_block(ebb0, &mut func.dfg, &mut func.layout, &mut func.jump_tables); ssa.seal_ebb_header_block(ebb0, &mut func);
let x_var = Variable(0); let x_var = Variable(0);
let x1 = { let x1 = {
let cur = &mut Cursor::new(&mut func.layout); let mut cur = FuncCursor::new(&mut func);
cur.insert_ebb(ebb0); cur.insert_ebb(ebb0);
cur.insert_ebb(ebb1); cur.insert_ebb(ebb1);
cur.goto_bottom(ebb0); cur.goto_bottom(ebb0);
func.dfg.ins(cur).iconst(I32, 1) cur.ins().iconst(I32, 1)
}; };
ssa.def_var(x_var, x1, block0); ssa.def_var(x_var, x1, block0);
let mut data = JumpTableData::new(); let mut data = JumpTableData::new();
data.push_entry(ebb1); data.push_entry(ebb1);
let jt = func.create_jump_table(data); let jt = func.create_jump_table(data);
ssa.use_var( ssa.use_var(&mut func, x_var, I32, block0).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block0,
).0;
let br_table = { let br_table = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).br_table(x1, jt) cur.ins().br_table(x1, jt)
}; };
let block1 = ssa.declare_ebb_body_block(block0); let block1 = ssa.declare_ebb_body_block(block0);
let x3 = { let x3 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).iconst(I32, 2) cur.ins().iconst(I32, 2)
}; };
ssa.def_var(x_var, x3, block1); ssa.def_var(x_var, x3, block1);
let jump_inst = { let jump_inst = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).jump(ebb1, &[]) cur.ins().jump(ebb1, &[])
}; };
let block2 = ssa.declare_ebb_header_block(ebb1); let block2 = ssa.declare_ebb_header_block(ebb1);
ssa.declare_ebb_predecessor(ebb1, block1, jump_inst); ssa.declare_ebb_predecessor(ebb1, block1, jump_inst);
ssa.declare_ebb_predecessor(ebb1, block0, br_table); ssa.declare_ebb_predecessor(ebb1, block0, br_table);
ssa.seal_ebb_header_block(ebb1, &mut func.dfg, &mut func.layout, &mut func.jump_tables); ssa.seal_ebb_header_block(ebb1, &mut func);
let x4 = ssa.use_var( let x4 = ssa.use_var(&mut func, x_var, I32, block2).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block2,
).0;
{ {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb1); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
func.dfg.ins(cur).iadd_imm(x4, 1) cur.ins().iadd_imm(x4, 1)
}; };
{ {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb1); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
func.dfg.ins(cur).return_(&[]) cur.ins().return_(&[])
}; };
let flags = settings::Flags::new(&settings::builder()); let flags = settings::Flags::new(&settings::builder());
match verify_function(&func, &flags) { match verify_function(&func, &flags) {
@@ -1197,82 +920,54 @@ mod tests {
let x_var = Variable(0); let x_var = Variable(0);
let y_var = Variable(1); let y_var = Variable(1);
let z_var = Variable(2); let z_var = Variable(2);
ssa.seal_ebb_header_block(ebb0, &mut func.dfg, &mut func.layout, &mut func.jump_tables); ssa.seal_ebb_header_block(ebb0, &mut func);
let x1 = { let x1 = {
let cur = &mut Cursor::new(&mut func.layout); let mut cur = FuncCursor::new(&mut func);
cur.insert_ebb(ebb0); cur.insert_ebb(ebb0);
cur.insert_ebb(ebb1); cur.insert_ebb(ebb1);
cur.goto_bottom(ebb0); cur.goto_bottom(ebb0);
func.dfg.ins(cur).iconst(I32, 0) cur.ins().iconst(I32, 0)
}; };
ssa.def_var(x_var, x1, block0); ssa.def_var(x_var, x1, block0);
let y1 = { let y1 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).iconst(I32, 1) cur.ins().iconst(I32, 1)
}; };
ssa.def_var(y_var, y1, block0); ssa.def_var(y_var, y1, block0);
let z1 = { let z1 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).iconst(I32, 2) cur.ins().iconst(I32, 2)
}; };
ssa.def_var(z_var, z1, block0); ssa.def_var(z_var, z1, block0);
let jump_inst = { let jump_inst = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb0); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb0);
func.dfg.ins(cur).jump(ebb1, &[]) cur.ins().jump(ebb1, &[])
}; };
let block1 = ssa.declare_ebb_header_block(ebb1); let block1 = ssa.declare_ebb_header_block(ebb1);
ssa.declare_ebb_predecessor(ebb1, block0, jump_inst); ssa.declare_ebb_predecessor(ebb1, block0, jump_inst);
let z2 = ssa.use_var( let z2 = ssa.use_var(&mut func, z_var, I32, block1).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
z_var,
I32,
block1,
).0;
assert_eq!(func.dfg.ebb_args(ebb1)[0], z2); assert_eq!(func.dfg.ebb_args(ebb1)[0], z2);
let x2 = ssa.use_var( let x2 = ssa.use_var(&mut func, x_var, I32, block1).0;
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block1,
).0;
assert_eq!(func.dfg.ebb_args(ebb1)[1], x2); assert_eq!(func.dfg.ebb_args(ebb1)[1], x2);
let x3 = { let x3 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb1); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
func.dfg.ins(cur).iadd(x2, z2) cur.ins().iadd(x2, z2)
}; };
ssa.def_var(x_var, x3, block1); ssa.def_var(x_var, x3, block1);
let x4 = ssa.use_var( let x4 = ssa.use_var(&mut func, x_var, I32, block1).0;
&mut func.dfg, let y3 = ssa.use_var(&mut func, y_var, I32, block1).0;
&mut func.layout,
&mut func.jump_tables,
x_var,
I32,
block1,
).0;
let y3 = ssa.use_var(
&mut func.dfg,
&mut func.layout,
&mut func.jump_tables,
y_var,
I32,
block1,
).0;
assert_eq!(func.dfg.ebb_args(ebb1)[2], y3); assert_eq!(func.dfg.ebb_args(ebb1)[2], y3);
let y4 = { let y4 = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb1); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
func.dfg.ins(cur).isub(y3, x4) cur.ins().isub(y3, x4)
}; };
ssa.def_var(y_var, y4, block1); ssa.def_var(y_var, y4, block1);
let jump_inst = { let jump_inst = {
let cur = &mut Cursor::new(&mut func.layout).at_bottom(ebb1); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
func.dfg.ins(cur).jump(ebb1, &[]) cur.ins().jump(ebb1, &[])
}; };
ssa.declare_ebb_predecessor(ebb1, block1, jump_inst); ssa.declare_ebb_predecessor(ebb1, block1, jump_inst);
ssa.seal_ebb_header_block(ebb1, &mut func.dfg, &mut func.layout, &mut func.jump_tables); ssa.seal_ebb_header_block(ebb1, &mut func);
// At sealing the "z" argument disappear but the remaining "x" and "y" args have to be // At sealing the "z" argument disappear but the remaining "x" and "y" args have to be
// in the right order. // in the right order.
assert_eq!(func.dfg.ebb_args(ebb1)[1], y3); assert_eq!(func.dfg.ebb_args(ebb1)[1], y3);