Use the term "EBB parameter" everywhere.

Add EBB parameter and EBB argument to the langref glossary to clarify
the distinction between formal EBB parameter values and arguments passed
to branches.

- Replace "ebb_arg" with "ebb_param" in function names that deal with
  EBB parameters.
- Rename the ValueDef variants to Result and Param.
- A bunch of other small langref fixes.

No functional changes intended.
This commit is contained in:
Jakob Stoklund Olesen
2017-10-19 14:15:23 -07:00
parent ea68a69f8b
commit 921bcc6c25
30 changed files with 392 additions and 366 deletions

View File

@@ -0,0 +1,13 @@
test verifier
function %gcd(i32 uext, i32 uext) -> i32 uext native {
fn1 = function %divmod(i32 uext, i32 uext) -> i32 uext, i32 uext
ebb1(v1: i32, v2: i32):
brz v2, ebb2
v3, v4 = call fn1(v1, v2)
return v3
ebb2:
return v1
}

View File

@@ -34,7 +34,7 @@ Here is the same function compiled into Cretonne IL:
:lines: 2- :lines: 2-
The first line of a function definition provides the function *name* and The first line of a function definition provides the function *name* and
the :term:`function signature` which declares the argument and return types. the :term:`function signature` which declares the parameter and return types.
Then follows the :term:`function preamble` which declares a number of entities Then follows the :term:`function preamble` which declares a number of entities
that can be referenced inside the function. In the example above, the preamble that can be referenced inside the function. In the example above, the preamble
declares a single local variable, ``ss1``. declares a single local variable, ``ss1``.
@@ -60,17 +60,18 @@ The instructions in the function body use and produce *values* in SSA form. This
means that every value is defined exactly once, and every use of a value must be means that every value is defined exactly once, and every use of a value must be
dominated by the definition. dominated by the definition.
Cretonne does not have phi instructions but uses *EBB arguments* instead. An EBB Cretonne does not have phi instructions but uses :term:`EBB parameter`\s
can be defined with a list of typed arguments. Whenever control is transferred instead. An EBB can be defined with a list of typed parameters. Whenever control
to the EBB, values for the arguments must be provided. When entering a function, is transferred to the EBB, argument values for the parameters must be provided.
the incoming function arguments are passed as arguments to the entry EBB. When entering a function, the incoming function parameters are passed as
arguments to the entry EBB's parameters.
Instructions define zero, one, or more result values. All SSA values are either Instructions define zero, one, or more result values. All SSA values are either
EBB arguments or instruction results. EBB parameters or instruction results.
In the example above, the loop induction variable ``i`` is represented as three In the example above, the loop induction variable ``i`` is represented as three
SSA values: In the entry block, ``v4`` is the initial value. In the loop block SSA values: In the entry block, ``v4`` is the initial value. In the loop block
``ebb2``, the EBB argument ``v5`` represents the value of the induction ``ebb2``, the EBB parameter ``v5`` represents the value of the induction
variable during each iteration. Finally, ``v12`` is computed as the induction variable during each iteration. Finally, ``v12`` is computed as the induction
variable value for the next iteration. variable value for the next iteration.
@@ -138,6 +139,7 @@ NaNs being indicated by the MSB of the trailing significand set to 0.
Except for bitwise and memory instructions, NaNs returned from arithmetic Except for bitwise and memory instructions, NaNs returned from arithmetic
instructions are encoded as follows: instructions are encoded as follows:
- If all NaN inputs to an instruction are quiet NaNs with all bits of the - If all NaN inputs to an instruction are quiet NaNs with all bits of the
trailing significand other than the MSB set to 0, the result is a quiet trailing significand other than the MSB set to 0, the result is a quiet
NaN with a nondeterministic sign bit and all bits of the trailing NaN with a nondeterministic sign bit and all bits of the trailing
@@ -160,6 +162,11 @@ Since some ISAs don't have CPU flags, these value types should not be used
until the legalization phase of compilation where the code is adapted to fit until the legalization phase of compilation where the code is adapted to fit
the target ISA. Use instructions like :inst:`icmp` instead. the target ISA. Use instructions like :inst:`icmp` instead.
The CPU flags types are also restricted such that two flags values can not be
live at the same time. After legalization, some instruction encodings will
clobber the flags, and flags values are not allowed to be live across such
instructions either. The verifier enforces these rules.
.. autoctontype:: iflags .. autoctontype:: iflags
.. autoctontype:: fflags .. autoctontype:: fflags
@@ -210,12 +217,12 @@ called a *lane*. The number of lanes must be a power of two in the range 2-256.
Pseudo-types and type classes Pseudo-types and type classes
----------------------------- -----------------------------
These are not concrete types, but convenient names uses to refer to real types These are not concrete types, but convenient names used to refer to real types
in this reference. in this reference.
.. type:: iAddr .. type:: iAddr
A Pointer-sized integer. A Pointer-sized integer representing an address.
This is either :type:`i32`, or :type:`i64`, depending on whether the target This is either :type:`i32`, or :type:`i64`, depending on whether the target
platform has 32-bit or 64-bit pointers. platform has 32-bit or 64-bit pointers.
@@ -379,21 +386,21 @@ Function calls
============== ==============
A function call needs a target function and a :term:`function signature`. The A function call needs a target function and a :term:`function signature`. The
target function may be determined dynamically at runtime, but the signature target function may be determined dynamically at runtime, but the signature must
must be known when the function call is compiled. The function signature be known when the function call is compiled. The function signature describes
describes how to call the function, including arguments, return values, and the how to call the function, including parameters, return values, and the calling
calling convention: convention:
.. productionlist:: .. productionlist::
signature : "(" [arglist] ")" ["->" retlist] [call_conv] signature : "(" [paramlist] ")" ["->" retlist] [call_conv]
arglist : arg { "," arg } paramlist : param { "," param }
retlist : arglist retlist : paramlist
arg : type [argext] [argspecial] param : type [paramext] [paramspecial]
argext : "uext" | "sext" paramext : "uext" | "sext"
argspecial: "sret" | "link" | "fp" | "csr" | "vmctx" paramspecial : "sret" | "link" | "fp" | "csr" | "vmctx"
callconv : `string` callconv : "native" | "spiderwasm"
Arguments and return values have flags whose meaning is mostly target Parameters and return values have flags whose meaning is mostly target
dependent. They make it possible to call native functions on the target dependent. They make it possible to call native functions on the target
platform. When calling other Cretonne functions, the flags are not necessary. platform. When calling other Cretonne functions, the flags are not necessary.
@@ -411,19 +418,11 @@ preamble`:
.. autoinst:: call .. autoinst:: call
.. autoinst:: x_return .. autoinst:: x_return
This simple example illustrates direct function calls and signatures:: This simple example illustrates direct function calls and signatures:
function %gcd(i32 uext, i32 uext) -> i32 uext "C" { .. literalinclude:: callex.cton
fn1 = function %divmod(i32 uext, i32 uext) -> i32 uext, i32 uext :language: cton
:lines: 3-
ebb1(v1: i32, v2: i32):
brz v2, ebb2
v3, v4 = call fn1(v1, v2)
br ebb1(v2, v4)
ebb2:
return v1
}
Indirect function calls use a signature declared in the preamble. Indirect function calls use a signature declared in the preamble.
@@ -682,15 +681,15 @@ bounds checking is required for each access:
Operations Operations
========== ==========
A few instructions have variants that take immediate operands (e.g.,
:inst:`band` / :inst:`band_imm`), but in general an instruction is required to
load a constant into an SSA value.
.. autoinst:: select .. autoinst:: select
Constant materialization Constant materialization
------------------------ ------------------------
A few instructions have variants that take immediate operands (e.g.,
:inst:`band` / :inst:`band_imm`), but in general an instruction is required to
load a constant into an SSA value.
.. autoinst:: iconst .. autoinst:: iconst
.. autoinst:: f32const .. autoinst:: f32const
.. autoinst:: f64const .. autoinst:: f64const
@@ -944,6 +943,9 @@ Instructions that can only be used by the Intel target ISA.
.. autoinst:: isa.intel.instructions.sdivmodx .. autoinst:: isa.intel.instructions.sdivmodx
.. autoinst:: isa.intel.instructions.udivmodx .. autoinst:: isa.intel.instructions.udivmodx
.. autoinst:: isa.intel.instructions.cvtt2si
.. autoinst:: isa.intel.instructions.fmin
.. autoinst:: isa.intel.instructions.fmax
Instruction groups Instruction groups
================== ==================
@@ -1034,6 +1036,18 @@ Glossary
control flow graph where only the root can be a join node. This control flow graph where only the root can be a join node. This
definition is not equivalent to Cretonne EBBs. definition is not equivalent to Cretonne EBBs.
EBB parameter
A formal parameter for an EBB is an SSA value that dominates everything
in the EBB. For each parameter declared by an EBB, a corresponding
argument value must be passed when branching to the EBB. The function's
entry EBB has parameters that correspond to the function's parameters.
EBB argument
Similar to function arguments, EBB arguments must be provided when
branching to an EBB that declares formal parameters. When execution
begins at the top of an EBB, the formal parameters have the values of
the arguments passed in the branch.
function signature function signature
A function signature describes how to call a function. It consists of: A function signature describes how to call a function. It consists of:

View File

@@ -1,12 +1,12 @@
test verifier test verifier
function %entry_block_signature_mismatch(i32) { function %entry_block_signature_mismatch(i32) {
ebb0: ; error: entry block arguments must match function signature ebb0: ; error: entry block parameters (0) must match function signature (1)
return return
} }
function %entry_block_arg_type(i32) { function %entry_block_arg_type(i32) {
ebb0(v0: f32): ; error: entry block argument 0 expected to have type i32, got f32 ebb0(v0: f32): ; error: entry block parameter 0 expected to have type i32, got f32
return return
} }

View File

@@ -450,7 +450,7 @@ mod test {
fn unreachable_node() { fn unreachable_node() {
let mut func = Function::new(); let mut func = Function::new();
let ebb0 = func.dfg.make_ebb(); let ebb0 = func.dfg.make_ebb();
let v0 = func.dfg.append_ebb_arg(ebb0, types::I32); let v0 = func.dfg.append_ebb_param(ebb0, types::I32);
let ebb1 = func.dfg.make_ebb(); let ebb1 = func.dfg.make_ebb();
let ebb2 = func.dfg.make_ebb(); let ebb2 = func.dfg.make_ebb();
@@ -479,7 +479,7 @@ mod test {
fn non_zero_entry_block() { fn non_zero_entry_block() {
let mut func = Function::new(); let mut func = Function::new();
let ebb3 = func.dfg.make_ebb(); let ebb3 = func.dfg.make_ebb();
let cond = func.dfg.append_ebb_arg(ebb3, types::I32); let cond = func.dfg.append_ebb_param(ebb3, types::I32);
let ebb1 = func.dfg.make_ebb(); let ebb1 = func.dfg.make_ebb();
let ebb2 = func.dfg.make_ebb(); let ebb2 = func.dfg.make_ebb();
let ebb0 = func.dfg.make_ebb(); let ebb0 = func.dfg.make_ebb();

View File

@@ -185,7 +185,7 @@ mod tests {
fn branches_and_jumps() { fn branches_and_jumps() {
let mut func = Function::new(); let mut func = Function::new();
let ebb0 = func.dfg.make_ebb(); let ebb0 = func.dfg.make_ebb();
let cond = func.dfg.append_ebb_arg(ebb0, types::I32); let cond = func.dfg.append_ebb_param(ebb0, types::I32);
let ebb1 = func.dfg.make_ebb(); let ebb1 = func.dfg.make_ebb();
let ebb2 = func.dfg.make_ebb(); let ebb2 = func.dfg.make_ebb();

View File

@@ -223,7 +223,7 @@ mod tests {
fn types() { fn types() {
let mut func = Function::new(); let mut func = Function::new();
let ebb0 = func.dfg.make_ebb(); let ebb0 = func.dfg.make_ebb();
let arg0 = func.dfg.append_ebb_arg(ebb0, I32); let arg0 = func.dfg.append_ebb_param(ebb0, I32);
let mut pos = FuncCursor::new(&mut func); let mut pos = FuncCursor::new(&mut func);
pos.insert_ebb(ebb0); pos.insert_ebb(ebb0);
@@ -244,14 +244,14 @@ mod tests {
fn reuse_results() { fn reuse_results() {
let mut func = Function::new(); let mut func = Function::new();
let ebb0 = func.dfg.make_ebb(); let ebb0 = func.dfg.make_ebb();
let arg0 = func.dfg.append_ebb_arg(ebb0, I32); let arg0 = func.dfg.append_ebb_param(ebb0, I32);
let mut pos = FuncCursor::new(&mut func); let mut pos = FuncCursor::new(&mut func);
pos.insert_ebb(ebb0); pos.insert_ebb(ebb0);
let v0 = pos.ins().iadd_imm(arg0, 17); let v0 = pos.ins().iadd_imm(arg0, 17);
assert_eq!(pos.func.dfg.value_type(v0), I32); assert_eq!(pos.func.dfg.value_type(v0), I32);
let iadd = pos.prev_inst().unwrap(); let iadd = pos.prev_inst().unwrap();
assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Res(iadd, 0)); assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iadd, 0));
// Detach v0 and reuse it for a different instruction. // Detach v0 and reuse it for a different instruction.
pos.func.dfg.clear_results(iadd); pos.func.dfg.clear_results(iadd);
@@ -260,6 +260,6 @@ mod tests {
assert_eq!(pos.current_inst(), Some(iadd)); assert_eq!(pos.current_inst(), Some(iadd));
let iconst = pos.prev_inst().unwrap(); let iconst = pos.prev_inst().unwrap();
assert!(iadd != iconst); assert!(iadd != iconst);
assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Res(iconst, 0)); assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iconst, 0));
} }
} }

View File

@@ -16,7 +16,7 @@ use std::u16;
/// A data flow graph defines all instructions and extended basic blocks in a function as well as /// A data flow graph defines all instructions and extended basic blocks in a function as well as
/// the data flow dependencies between them. The DFG also tracks values which can be either /// the data flow dependencies between them. The DFG also tracks values which can be either
/// instruction results or EBB arguments. /// instruction results or EBB parameters.
/// ///
/// The layout of EBBs in the function and of instructions in each EBB is recorded by the /// The layout of EBBs in the function and of instructions in each EBB is recorded by the
/// `FunctionLayout` data structure which form the other half of the function representation. /// `FunctionLayout` data structure which form the other half of the function representation.
@@ -34,7 +34,8 @@ pub struct DataFlowGraph {
/// primary `insts` map. /// primary `insts` map.
results: EntityMap<Inst, ValueList>, results: EntityMap<Inst, ValueList>,
/// Extended basic blocks in the function and their arguments. /// Extended basic blocks in the function and their parameters.
///
/// This map is not in program order. That is handled by `Layout`, and so is the sequence of /// This map is not in program order. That is handled by `Layout`, and so is the sequence of
/// instructions contained in each EBB. /// instructions contained in each EBB.
ebbs: PrimaryMap<Ebb, EbbData>, ebbs: PrimaryMap<Ebb, EbbData>,
@@ -45,7 +46,7 @@ pub struct DataFlowGraph {
/// ///
/// - Instructions in `insts` that don't have room for their entire argument list inline. /// - Instructions in `insts` that don't have room for their entire argument list inline.
/// - Instruction result values in `results`. /// - Instruction result values in `results`.
/// - EBB arguments in `ebbs`. /// - EBB parameters in `ebbs`.
pub value_lists: ValueListPool, pub value_lists: ValueListPool,
/// Primary value table with entries for all values. /// Primary value table with entries for all values.
@@ -135,7 +136,7 @@ fn resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Value
/// Handling values. /// Handling values.
/// ///
/// Values are either EBB arguments or instruction results. /// Values are either EBB parameters or instruction results.
impl DataFlowGraph { impl DataFlowGraph {
/// Allocate an extended value entry. /// Allocate an extended value entry.
fn make_value(&mut self, data: ValueData) -> Value { fn make_value(&mut self, data: ValueData) -> Value {
@@ -151,7 +152,7 @@ impl DataFlowGraph {
pub fn value_type(&self, v: Value) -> Type { pub fn value_type(&self, v: Value) -> Type {
match self.values[v] { match self.values[v] {
ValueData::Inst { ty, .. } | ValueData::Inst { ty, .. } |
ValueData::Arg { ty, .. } | ValueData::Param { ty, .. } |
ValueData::Alias { ty, .. } => ty, ValueData::Alias { ty, .. } => ty,
} }
} }
@@ -159,7 +160,7 @@ impl DataFlowGraph {
/// Get the definition of a value. /// Get the definition of a value.
/// ///
/// This is either the instruction that defined it or the Ebb that has the value as an /// This is either the instruction that defined it or the Ebb that has the value as an
/// argument. /// parameter.
pub fn value_def(&self, v: Value) -> ValueDef { pub fn value_def(&self, v: Value) -> ValueDef {
match self.values[v] { match self.values[v] {
ValueData::Inst { inst, num, .. } => { ValueData::Inst { inst, num, .. } => {
@@ -170,15 +171,15 @@ impl DataFlowGraph {
v, v,
self.display_inst(inst, None) self.display_inst(inst, None)
); );
ValueDef::Res(inst, num as usize) ValueDef::Result(inst, num as usize)
} }
ValueData::Arg { ebb, num, .. } => { ValueData::Param { ebb, num, .. } => {
assert_eq!( assert_eq!(
Some(v), Some(v),
self.ebbs[ebb].args.get(num as usize, &self.value_lists), self.ebbs[ebb].params.get(num as usize, &self.value_lists),
"Dangling EBB argument value" "Dangling EBB parameter value"
); );
ValueDef::Arg(ebb, num as usize) ValueDef::Param(ebb, num as usize)
} }
ValueData::Alias { original, .. } => { ValueData::Alias { original, .. } => {
// Make sure we only recurse one level. `resolve_aliases` has safeguards to // Make sure we only recurse one level. `resolve_aliases` has safeguards to
@@ -188,7 +189,7 @@ impl DataFlowGraph {
} }
} }
/// Determine if `v` is an attached instruction result / EBB argument. /// Determine if `v` is an attached instruction result / EBB parameter.
/// ///
/// An attached value can't be attached to something else without first being detached. /// An attached value can't be attached to something else without first being detached.
/// ///
@@ -198,7 +199,7 @@ impl DataFlowGraph {
use self::ValueData::*; use self::ValueData::*;
match self.values[v] { match self.values[v] {
Inst { inst, num, .. } => Some(&v) == self.inst_results(inst).get(num as usize), Inst { inst, num, .. } => Some(&v) == self.inst_results(inst).get(num as usize),
Arg { ebb, num, .. } => Some(&v) == self.ebb_args(ebb).get(num as usize), Param { ebb, num, .. } => Some(&v) == self.ebb_params(ebb).get(num as usize),
Alias { .. } => false, Alias { .. } => false,
} }
} }
@@ -317,16 +318,16 @@ impl DataFlowGraph {
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum ValueDef { pub enum ValueDef {
/// Value is the n'th result of an instruction. /// Value is the n'th result of an instruction.
Res(Inst, usize), Result(Inst, usize),
/// Value is the n'th argument to an EBB. /// Value is the n'th parameter to an EBB.
Arg(Ebb, usize), Param(Ebb, usize),
} }
impl ValueDef { impl ValueDef {
/// Unwrap the instruction where the value was defined, or panic. /// Unwrap the instruction where the value was defined, or panic.
pub fn unwrap_inst(&self) -> Inst { pub fn unwrap_inst(&self) -> Inst {
match *self { match *self {
ValueDef::Res(inst, _) => inst, ValueDef::Result(inst, _) => inst,
_ => panic!("Value is not an instruction result"), _ => panic!("Value is not an instruction result"),
} }
} }
@@ -338,11 +339,11 @@ enum ValueData {
// Value is defined by an instruction. // Value is defined by an instruction.
Inst { ty: Type, num: u16, inst: Inst }, Inst { ty: Type, num: u16, inst: Inst },
// Value is an EBB argument. // Value is an EBB parameter.
Arg { ty: Type, num: u16, ebb: Ebb }, Param { ty: Type, num: u16, ebb: Ebb },
// Value is an alias of another value. // Value is an alias of another value.
// An alias value can't be linked as an instruction result or EBB argument. It is used as a // An alias value can't be linked as an instruction result or EBB parameter. It is used as a
// placeholder when the original instruction or EBB has been rewritten or modified. // placeholder when the original instruction or EBB has been rewritten or modified.
Alias { ty: Type, original: Value }, Alias { ty: Type, original: Value },
} }
@@ -678,83 +679,82 @@ impl DataFlowGraph {
self.ebbs.push(EbbData::new()) self.ebbs.push(EbbData::new())
} }
/// Get the number of arguments on `ebb`. /// Get the number of parameters on `ebb`.
pub fn num_ebb_args(&self, ebb: Ebb) -> usize { pub fn num_ebb_params(&self, ebb: Ebb) -> usize {
self.ebbs[ebb].args.len(&self.value_lists) self.ebbs[ebb].params.len(&self.value_lists)
} }
/// Get the arguments to an EBB. /// Get the parameters on `ebb`.
pub fn ebb_args(&self, ebb: Ebb) -> &[Value] { pub fn ebb_params(&self, ebb: Ebb) -> &[Value] {
self.ebbs[ebb].args.as_slice(&self.value_lists) self.ebbs[ebb].params.as_slice(&self.value_lists)
} }
/// Append an argument with type `ty` to `ebb`. /// Append a parameter with type `ty` to `ebb`.
pub fn append_ebb_arg(&mut self, ebb: Ebb, ty: Type) -> Value { pub fn append_ebb_param(&mut self, ebb: Ebb, ty: Type) -> Value {
let arg = self.values.next_key(); let param = self.values.next_key();
let num = self.ebbs[ebb].args.push(arg, &mut self.value_lists); let num = self.ebbs[ebb].params.push(param, &mut self.value_lists);
assert!(num <= u16::MAX as usize, "Too many arguments to EBB"); assert!(num <= u16::MAX as usize, "Too many parameters on EBB");
self.make_value(ValueData::Arg { self.make_value(ValueData::Param {
ty, ty,
num: num as u16, num: num as u16,
ebb, ebb,
}) })
} }
/// Removes `val` from `ebb`'s argument by swapping it with the last argument of `ebb`. /// Removes `val` from `ebb`'s parameters by swapping it with the last parameter on `ebb`.
/// Returns the position of `val` before removal. /// Returns the position of `val` before removal.
/// ///
/// *Important*: to ensure O(1) deletion, this method swaps the removed argument with the /// *Important*: to ensure O(1) deletion, this method swaps the removed parameter with the
/// last `Ebb` argument. This can disrupt all the branch instructions jumping to this /// last `ebb`` parameter. This can disrupt all the branch instructions jumping to this
/// `Ebb` for which you have to change the jump argument order if necessary. /// `ebb` for which you have to change the branch argument order if necessary.
/// ///
/// Panics if `val` is not an `Ebb` argument. Returns `true` if `Ebb` arguments have been /// Panics if `val` is not an EBB parameter.
/// swapped. pub fn swap_remove_ebb_param(&mut self, val: Value) -> usize {
pub fn swap_remove_ebb_arg(&mut self, val: Value) -> usize { let (ebb, num) = if let ValueData::Param { num, ebb, .. } = self.values[val] {
let (ebb, num) = if let ValueData::Arg { num, ebb, .. } = self.values[val] {
(ebb, num) (ebb, num)
} else { } else {
panic!("{} must be an EBB argument", val); panic!("{} must be an EBB parameter", val);
}; };
self.ebbs[ebb].args.swap_remove( self.ebbs[ebb].params.swap_remove(
num as usize, num as usize,
&mut self.value_lists, &mut self.value_lists,
); );
if let Some(last_arg_val) = self.ebbs[ebb].args.get(num as usize, &self.value_lists) { if let Some(last_arg_val) = self.ebbs[ebb].params.get(num as usize, &self.value_lists) {
// We update the position of the old last arg. // We update the position of the old last arg.
if let ValueData::Arg { num: ref mut old_num, .. } = self.values[last_arg_val] { if let ValueData::Param { num: ref mut old_num, .. } = self.values[last_arg_val] {
*old_num = num; *old_num = num;
} else { } else {
panic!("{} should be an Ebb argument but is not", last_arg_val); panic!("{} should be an Ebb parameter", last_arg_val);
} }
} }
num as usize num as usize
} }
/// Removes `val` from `ebb`'s arguments by a standard linear time list removal which preserves /// Removes `val` from `ebb`'s parameters by a standard linear time list removal which
/// ordering. Also updates the values' data. /// preserves ordering. Also updates the values' data.
pub fn remove_ebb_arg(&mut self, val: Value) { pub fn remove_ebb_param(&mut self, val: Value) {
let (ebb, num) = if let ValueData::Arg { num, ebb, .. } = self.values[val] { let (ebb, num) = if let ValueData::Param { num, ebb, .. } = self.values[val] {
(ebb, num) (ebb, num)
} else { } else {
panic!("{} must be an EBB argument", val); panic!("{} must be an EBB parameter", val);
}; };
self.ebbs[ebb].args.remove( self.ebbs[ebb].params.remove(
num as usize, num as usize,
&mut self.value_lists, &mut self.value_lists,
); );
for index in num..(self.ebb_args(ebb).len() as u16) { for index in num..(self.num_ebb_params(ebb) as u16) {
match self.values[self.ebbs[ebb] match self.values[self.ebbs[ebb]
.args .params
.get(index as usize, &self.value_lists) .get(index as usize, &self.value_lists)
.unwrap()] { .unwrap()] {
ValueData::Arg { ref mut num, .. } => { ValueData::Param { ref mut num, .. } => {
*num -= 1; *num -= 1;
} }
_ => { _ => {
panic!( panic!(
"{} must be an EBB argument", "{} must be an EBB parameter",
self.ebbs[ebb] self.ebbs[ebb]
.args .params
.get(index as usize, &self.value_lists) .get(index as usize, &self.value_lists)
.unwrap() .unwrap()
) )
@@ -764,73 +764,73 @@ impl DataFlowGraph {
} }
/// Append an existing argument value to `ebb`. /// Append an existing value to `ebb`'s parameters.
/// ///
/// The appended value can't already be attached to something else. /// The appended value can't already be attached to something else.
/// ///
/// In almost all cases, you should be using `append_ebb_arg()` instead of this method. /// In almost all cases, you should be using `append_ebb_param()` instead of this method.
pub fn attach_ebb_arg(&mut self, ebb: Ebb, arg: Value) { pub fn attach_ebb_param(&mut self, ebb: Ebb, param: Value) {
assert!(!self.value_is_attached(arg)); assert!(!self.value_is_attached(param));
let num = self.ebbs[ebb].args.push(arg, &mut self.value_lists); let num = self.ebbs[ebb].params.push(param, &mut self.value_lists);
assert!(num <= u16::MAX as usize, "Too many arguments to EBB"); assert!(num <= u16::MAX as usize, "Too many parameters on EBB");
let ty = self.value_type(arg); let ty = self.value_type(param);
self.values[arg] = ValueData::Arg { self.values[param] = ValueData::Param {
ty, ty,
num: num as u16, num: num as u16,
ebb, ebb,
}; };
} }
/// Replace an EBB argument with a new value of type `ty`. /// Replace an EBB parameter with a new value of type `ty`.
/// ///
/// The `old_value` must be an attached EBB argument. It is removed from its place in the list /// The `old_value` must be an attached EBB parameter. It is removed from its place in the list
/// of arguments and replaced by a new value of type `new_type`. The new value gets the same /// of parameters and replaced by a new value of type `new_type`. The new value gets the same
/// position in the list, and other arguments are not disturbed. /// position in the list, and other parameters are not disturbed.
/// ///
/// The old value is left detached, so it should probably be changed into something else. /// The old value is left detached, so it should probably be changed into something else.
/// ///
/// Returns the new value. /// Returns the new value.
pub fn replace_ebb_arg(&mut self, old_arg: Value, new_type: Type) -> Value { pub fn replace_ebb_param(&mut self, old_value: Value, new_type: Type) -> Value {
// Create new value identical to the old one except for the type. // Create new value identical to the old one except for the type.
let (ebb, num) = if let ValueData::Arg { num, ebb, .. } = self.values[old_arg] { let (ebb, num) = if let ValueData::Param { num, ebb, .. } = self.values[old_value] {
(ebb, num) (ebb, num)
} else { } else {
panic!("{} must be an EBB argument", old_arg); panic!("{} must be an EBB parameter", old_value);
}; };
let new_arg = self.make_value(ValueData::Arg { let new_arg = self.make_value(ValueData::Param {
ty: new_type, ty: new_type,
num, num,
ebb, ebb,
}); });
self.ebbs[ebb].args.as_mut_slice(&mut self.value_lists)[num as usize] = new_arg; self.ebbs[ebb].params.as_mut_slice(&mut self.value_lists)[num as usize] = new_arg;
new_arg new_arg
} }
/// Detach all the arguments from `ebb` and return them as a `ValueList`. /// Detach all the parameters from `ebb` and return them as a `ValueList`.
/// ///
/// This is a quite low-level operation. Sensible things to do with the detached EBB arguments /// This is a quite low-level operation. Sensible things to do with the detached EBB parameters
/// is to put them back on the same EBB with `attach_ebb_arg()` or change them into aliases /// is to put them back on the same EBB with `attach_ebb_param()` or change them into aliases
/// with `change_to_alias()`. /// with `change_to_alias()`.
pub fn detach_ebb_args(&mut self, ebb: Ebb) -> ValueList { pub fn detach_ebb_params(&mut self, ebb: Ebb) -> ValueList {
self.ebbs[ebb].args.take() self.ebbs[ebb].params.take()
} }
} }
// Contents of an extended basic block. // Contents of an extended basic block.
// //
// Arguments for an extended basic block are values that dominate everything in the EBB. All // Parameters on an extended basic block are values that dominate everything in the EBB. All
// branches to this EBB must provide matching arguments, and the arguments to the entry EBB must // branches to this EBB must provide matching arguments, and the arguments to the entry EBB must
// match the function arguments. // match the function arguments.
#[derive(Clone)] #[derive(Clone)]
struct EbbData { struct EbbData {
// List of arguments to this EBB. // List of parameters to this EBB.
args: ValueList, params: ValueList,
} }
impl EbbData { impl EbbData {
fn new() -> EbbData { fn new() -> EbbData {
EbbData { args: ValueList::new() } EbbData { params: ValueList::new() }
} }
} }
@@ -899,7 +899,7 @@ mod tests {
let val = dfg.first_result(inst); let val = dfg.first_result(inst);
assert_eq!(dfg.inst_results(inst), &[val]); assert_eq!(dfg.inst_results(inst), &[val]);
assert_eq!(dfg.value_def(val), ValueDef::Res(inst, 0)); assert_eq!(dfg.value_def(val), ValueDef::Result(inst, 0));
assert_eq!(dfg.value_type(val), types::I32); assert_eq!(dfg.value_type(val), types::I32);
// Replacing results. // Replacing results.
@@ -908,7 +908,7 @@ mod tests {
assert!(!dfg.value_is_attached(val)); assert!(!dfg.value_is_attached(val));
assert!(dfg.value_is_attached(v2)); assert!(dfg.value_is_attached(v2));
assert_eq!(dfg.inst_results(inst), &[v2]); assert_eq!(dfg.inst_results(inst), &[v2]);
assert_eq!(dfg.value_def(v2), ValueDef::Res(inst, 0)); assert_eq!(dfg.value_def(v2), ValueDef::Result(inst, 0));
assert_eq!(dfg.value_type(v2), types::F64); assert_eq!(dfg.value_type(v2), types::F64);
} }
@@ -933,90 +933,90 @@ mod tests {
let ebb = dfg.make_ebb(); let ebb = dfg.make_ebb();
assert_eq!(ebb.to_string(), "ebb0"); assert_eq!(ebb.to_string(), "ebb0");
assert_eq!(dfg.num_ebb_args(ebb), 0); assert_eq!(dfg.num_ebb_params(ebb), 0);
assert_eq!(dfg.ebb_args(ebb), &[]); assert_eq!(dfg.ebb_params(ebb), &[]);
assert!(dfg.detach_ebb_args(ebb).is_empty()); assert!(dfg.detach_ebb_params(ebb).is_empty());
assert_eq!(dfg.num_ebb_args(ebb), 0); assert_eq!(dfg.num_ebb_params(ebb), 0);
assert_eq!(dfg.ebb_args(ebb), &[]); assert_eq!(dfg.ebb_params(ebb), &[]);
let arg1 = dfg.append_ebb_arg(ebb, types::F32); let arg1 = dfg.append_ebb_param(ebb, types::F32);
assert_eq!(arg1.to_string(), "v0"); assert_eq!(arg1.to_string(), "v0");
assert_eq!(dfg.num_ebb_args(ebb), 1); assert_eq!(dfg.num_ebb_params(ebb), 1);
assert_eq!(dfg.ebb_args(ebb), &[arg1]); assert_eq!(dfg.ebb_params(ebb), &[arg1]);
let arg2 = dfg.append_ebb_arg(ebb, types::I16); let arg2 = dfg.append_ebb_param(ebb, types::I16);
assert_eq!(arg2.to_string(), "v1"); assert_eq!(arg2.to_string(), "v1");
assert_eq!(dfg.num_ebb_args(ebb), 2); assert_eq!(dfg.num_ebb_params(ebb), 2);
assert_eq!(dfg.ebb_args(ebb), &[arg1, arg2]); assert_eq!(dfg.ebb_params(ebb), &[arg1, arg2]);
assert_eq!(dfg.value_def(arg1), ValueDef::Arg(ebb, 0)); assert_eq!(dfg.value_def(arg1), ValueDef::Param(ebb, 0));
assert_eq!(dfg.value_def(arg2), ValueDef::Arg(ebb, 1)); assert_eq!(dfg.value_def(arg2), ValueDef::Param(ebb, 1));
assert_eq!(dfg.value_type(arg1), types::F32); assert_eq!(dfg.value_type(arg1), types::F32);
assert_eq!(dfg.value_type(arg2), types::I16); assert_eq!(dfg.value_type(arg2), types::I16);
// Swap the two EBB arguments. // Swap the two EBB parameters.
let vlist = dfg.detach_ebb_args(ebb); let vlist = dfg.detach_ebb_params(ebb);
assert_eq!(dfg.num_ebb_args(ebb), 0); assert_eq!(dfg.num_ebb_params(ebb), 0);
assert_eq!(dfg.ebb_args(ebb), &[]); assert_eq!(dfg.ebb_params(ebb), &[]);
assert_eq!(vlist.as_slice(&dfg.value_lists), &[arg1, arg2]); assert_eq!(vlist.as_slice(&dfg.value_lists), &[arg1, arg2]);
dfg.attach_ebb_arg(ebb, arg2); dfg.attach_ebb_param(ebb, arg2);
let arg3 = dfg.append_ebb_arg(ebb, types::I32); let arg3 = dfg.append_ebb_param(ebb, types::I32);
dfg.attach_ebb_arg(ebb, arg1); dfg.attach_ebb_param(ebb, arg1);
assert_eq!(dfg.ebb_args(ebb), &[arg2, arg3, arg1]); assert_eq!(dfg.ebb_params(ebb), &[arg2, arg3, arg1]);
} }
#[test] #[test]
fn replace_ebb_arguments() { fn replace_ebb_params() {
let mut dfg = DataFlowGraph::new(); let mut dfg = DataFlowGraph::new();
let ebb = dfg.make_ebb(); let ebb = dfg.make_ebb();
let arg1 = dfg.append_ebb_arg(ebb, types::F32); let arg1 = dfg.append_ebb_param(ebb, types::F32);
let new1 = dfg.replace_ebb_arg(arg1, types::I64); let new1 = dfg.replace_ebb_param(arg1, types::I64);
assert_eq!(dfg.value_type(arg1), types::F32); assert_eq!(dfg.value_type(arg1), types::F32);
assert_eq!(dfg.value_type(new1), types::I64); assert_eq!(dfg.value_type(new1), types::I64);
assert_eq!(dfg.ebb_args(ebb), &[new1]); assert_eq!(dfg.ebb_params(ebb), &[new1]);
dfg.attach_ebb_arg(ebb, arg1); dfg.attach_ebb_param(ebb, arg1);
assert_eq!(dfg.ebb_args(ebb), &[new1, arg1]); assert_eq!(dfg.ebb_params(ebb), &[new1, arg1]);
let new2 = dfg.replace_ebb_arg(arg1, types::I8); let new2 = dfg.replace_ebb_param(arg1, types::I8);
assert_eq!(dfg.value_type(arg1), types::F32); assert_eq!(dfg.value_type(arg1), types::F32);
assert_eq!(dfg.value_type(new2), types::I8); assert_eq!(dfg.value_type(new2), types::I8);
assert_eq!(dfg.ebb_args(ebb), &[new1, new2]); assert_eq!(dfg.ebb_params(ebb), &[new1, new2]);
dfg.attach_ebb_arg(ebb, arg1); dfg.attach_ebb_param(ebb, arg1);
assert_eq!(dfg.ebb_args(ebb), &[new1, new2, arg1]); assert_eq!(dfg.ebb_params(ebb), &[new1, new2, arg1]);
let new3 = dfg.replace_ebb_arg(new2, types::I16); let new3 = dfg.replace_ebb_param(new2, types::I16);
assert_eq!(dfg.value_type(new1), types::I64); assert_eq!(dfg.value_type(new1), types::I64);
assert_eq!(dfg.value_type(new2), types::I8); assert_eq!(dfg.value_type(new2), types::I8);
assert_eq!(dfg.value_type(new3), types::I16); assert_eq!(dfg.value_type(new3), types::I16);
assert_eq!(dfg.ebb_args(ebb), &[new1, new3, arg1]); assert_eq!(dfg.ebb_params(ebb), &[new1, new3, arg1]);
} }
#[test] #[test]
fn swap_remove_ebb_arguments() { fn swap_remove_ebb_params() {
let mut dfg = DataFlowGraph::new(); let mut dfg = DataFlowGraph::new();
let ebb = dfg.make_ebb(); let ebb = dfg.make_ebb();
let arg1 = dfg.append_ebb_arg(ebb, types::F32); let arg1 = dfg.append_ebb_param(ebb, types::F32);
let arg2 = dfg.append_ebb_arg(ebb, types::F32); let arg2 = dfg.append_ebb_param(ebb, types::F32);
let arg3 = dfg.append_ebb_arg(ebb, types::F32); let arg3 = dfg.append_ebb_param(ebb, types::F32);
assert_eq!(dfg.ebb_args(ebb), &[arg1, arg2, arg3]); assert_eq!(dfg.ebb_params(ebb), &[arg1, arg2, arg3]);
dfg.swap_remove_ebb_arg(arg1); dfg.swap_remove_ebb_param(arg1);
assert_eq!(dfg.value_is_attached(arg1), false); assert_eq!(dfg.value_is_attached(arg1), false);
assert_eq!(dfg.value_is_attached(arg2), true); assert_eq!(dfg.value_is_attached(arg2), true);
assert_eq!(dfg.value_is_attached(arg3), true); assert_eq!(dfg.value_is_attached(arg3), true);
assert_eq!(dfg.ebb_args(ebb), &[arg3, arg2]); assert_eq!(dfg.ebb_params(ebb), &[arg3, arg2]);
dfg.swap_remove_ebb_arg(arg2); dfg.swap_remove_ebb_param(arg2);
assert_eq!(dfg.value_is_attached(arg2), false); assert_eq!(dfg.value_is_attached(arg2), false);
assert_eq!(dfg.value_is_attached(arg3), true); assert_eq!(dfg.value_is_attached(arg3), true);
assert_eq!(dfg.ebb_args(ebb), &[arg3]); assert_eq!(dfg.ebb_params(ebb), &[arg3]);
dfg.swap_remove_ebb_arg(arg3); dfg.swap_remove_ebb_param(arg3);
assert_eq!(dfg.value_is_attached(arg3), false); assert_eq!(dfg.value_is_attached(arg3), false);
assert_eq!(dfg.ebb_args(ebb), &[]); assert_eq!(dfg.ebb_params(ebb), &[]);
} }
#[test] #[test]
@@ -1035,10 +1035,10 @@ mod tests {
// Make sure we can resolve value aliases even when values is empty. // Make sure we can resolve value aliases even when values is empty.
assert_eq!(pos.func.dfg.resolve_aliases(v1), v1); assert_eq!(pos.func.dfg.resolve_aliases(v1), v1);
let arg0 = pos.func.dfg.append_ebb_arg(ebb0, types::I32); let arg0 = pos.func.dfg.append_ebb_param(ebb0, types::I32);
let (s, c) = pos.ins().iadd_cout(v1, arg0); let (s, c) = pos.ins().iadd_cout(v1, arg0);
let iadd = match pos.func.dfg.value_def(s) { let iadd = match pos.func.dfg.value_def(s) {
ValueDef::Res(i, 0) => i, ValueDef::Result(i, 0) => i,
_ => panic!(), _ => panic!(),
}; };

View File

@@ -150,7 +150,7 @@ impl Function {
pub fn special_arg(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> { pub fn special_arg(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> {
let entry = self.layout.entry_block().expect("Function is empty"); let entry = self.layout.entry_block().expect("Function is empty");
self.signature.special_arg_index(purpose).map(|i| { self.signature.special_arg_index(purpose).map(|i| {
self.dfg.ebb_args(entry)[i] self.dfg.ebb_params(entry)[i]
}) })
} }
} }

View File

@@ -35,8 +35,8 @@ impl From<Ebb> for ProgramPoint {
impl From<ValueDef> for ProgramPoint { impl From<ValueDef> for ProgramPoint {
fn from(def: ValueDef) -> ProgramPoint { fn from(def: ValueDef) -> ProgramPoint {
match def { match def {
ValueDef::Res(inst, _) => inst.into(), ValueDef::Result(inst, _) => inst.into(),
ValueDef::Arg(ebb, _) => ebb.into(), ValueDef::Param(ebb, _) => ebb.into(),
} }
} }
} }
@@ -66,8 +66,8 @@ impl From<Ebb> for ExpandedProgramPoint {
impl From<ValueDef> for ExpandedProgramPoint { impl From<ValueDef> for ExpandedProgramPoint {
fn from(def: ValueDef) -> ExpandedProgramPoint { fn from(def: ValueDef) -> ExpandedProgramPoint {
match def { match def {
ValueDef::Res(inst, _) => inst.into(), ValueDef::Result(inst, _) => inst.into(),
ValueDef::Arg(ebb, _) => ebb.into(), ValueDef::Param(ebb, _) => ebb.into(),
} }
} }
} }

View File

@@ -37,7 +37,7 @@ fn expand_srem(inst: ir::Inst, func: &mut ir::Function, cfg: &mut ControlFlowGra
let result = func.dfg.first_result(inst); let result = func.dfg.first_result(inst);
let ty = func.dfg.value_type(result); let ty = func.dfg.value_type(result);
func.dfg.clear_results(inst); func.dfg.clear_results(inst);
func.dfg.attach_ebb_arg(done, result); func.dfg.attach_ebb_param(done, result);
let mut pos = FuncCursor::new(func).at_inst(inst); let mut pos = FuncCursor::new(func).at_inst(inst);
pos.use_srcloc(inst); pos.use_srcloc(inst);
@@ -112,7 +112,7 @@ fn expand_minmax(inst: ir::Inst, func: &mut ir::Function, cfg: &mut ControlFlowG
let result = func.dfg.first_result(inst); let result = func.dfg.first_result(inst);
let ty = func.dfg.value_type(result); let ty = func.dfg.value_type(result);
func.dfg.clear_results(inst); func.dfg.clear_results(inst);
func.dfg.attach_ebb_arg(done, result); func.dfg.attach_ebb_param(done, result);
// Test for case 1) ordered and not equal. // Test for case 1) ordered and not equal.
let mut pos = FuncCursor::new(func).at_inst(inst); let mut pos = FuncCursor::new(func).at_inst(inst);
@@ -194,7 +194,7 @@ fn expand_fcvt_from_uint(inst: ir::Inst, func: &mut ir::Function, cfg: &mut Cont
// Move the `inst` result value onto the `done` EBB. // Move the `inst` result value onto the `done` EBB.
pos.func.dfg.clear_results(inst); pos.func.dfg.clear_results(inst);
pos.func.dfg.attach_ebb_arg(done, result); pos.func.dfg.attach_ebb_param(done, result);
// If x as a signed int is not negative, we can use the existing `fcvt_from_sint` instruction. // If x as a signed int is not negative, we can use the existing `fcvt_from_sint` instruction.
let is_neg = pos.ins().icmp_imm(IntCC::SignedLessThan, x, 0); let is_neg = pos.ins().icmp_imm(IntCC::SignedLessThan, x, 0);
@@ -328,7 +328,7 @@ fn expand_fcvt_to_uint(inst: ir::Inst, func: &mut ir::Function, cfg: &mut Contro
// Move the `inst` result value onto the `done` EBB. // Move the `inst` result value onto the `done` EBB.
func.dfg.clear_results(inst); func.dfg.clear_results(inst);
func.dfg.attach_ebb_arg(done, result); func.dfg.attach_ebb_param(done, result);
let mut pos = FuncCursor::new(func).at_inst(inst); let mut pos = FuncCursor::new(func).at_inst(inst);
pos.use_srcloc(inst); pos.use_srcloc(inst);

View File

@@ -136,8 +136,8 @@ mod tests {
let mut dfg = DataFlowGraph::new(); let mut dfg = DataFlowGraph::new();
let ebb = dfg.make_ebb(); let ebb = dfg.make_ebb();
let arg64 = dfg.append_ebb_arg(ebb, types::I64); let arg64 = dfg.append_ebb_param(ebb, types::I64);
let arg32 = dfg.append_ebb_arg(ebb, types::I32); let arg32 = dfg.append_ebb_param(ebb, types::I32);
// Try to encode iadd_imm.i64 v1, -10. // Try to encode iadd_imm.i64 v1, -10.
let inst64 = InstructionData::BinaryImm { let inst64 = InstructionData::BinaryImm {
@@ -180,8 +180,8 @@ mod tests {
let mut dfg = DataFlowGraph::new(); let mut dfg = DataFlowGraph::new();
let ebb = dfg.make_ebb(); let ebb = dfg.make_ebb();
let arg64 = dfg.append_ebb_arg(ebb, types::I64); let arg64 = dfg.append_ebb_param(ebb, types::I64);
let arg32 = dfg.append_ebb_arg(ebb, types::I32); let arg32 = dfg.append_ebb_param(ebb, types::I32);
// Try to encode iadd_imm.i64 v1, -10. // Try to encode iadd_imm.i64 v1, -10.
let inst64 = InstructionData::BinaryImm { let inst64 = InstructionData::BinaryImm {
@@ -237,7 +237,7 @@ mod tests {
let mut dfg = DataFlowGraph::new(); let mut dfg = DataFlowGraph::new();
let ebb = dfg.make_ebb(); let ebb = dfg.make_ebb();
let arg32 = dfg.append_ebb_arg(ebb, types::I32); let arg32 = dfg.append_ebb_param(ebb, types::I32);
// Create an imul.i32 which is encodable in RV32M. // Create an imul.i32 which is encodable in RV32M.
let mul32 = InstructionData::Binary { let mul32 = InstructionData::Binary {

View File

@@ -67,11 +67,11 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) {
// Keep track of the argument types in the ABI-legalized signature. // Keep track of the argument types in the ABI-legalized signature.
let mut abi_arg = 0; let mut abi_arg = 0;
// Process the EBB arguments one at a time, possibly replacing one argument with multiple new // Process the EBB parameters one at a time, possibly replacing one argument with multiple new
// ones. We do this by detaching the entry EBB arguments first. // ones. We do this by detaching the entry EBB parameters first.
let ebb_args = pos.func.dfg.detach_ebb_args(entry); let ebb_params = pos.func.dfg.detach_ebb_params(entry);
let mut old_arg = 0; let mut old_arg = 0;
while let Some(arg) = ebb_args.get(old_arg, &pos.func.dfg.value_lists) { while let Some(arg) = ebb_params.get(old_arg, &pos.func.dfg.value_lists) {
old_arg += 1; old_arg += 1;
let abi_type = pos.func.signature.argument_types[abi_arg]; let abi_type = pos.func.signature.argument_types[abi_arg];
@@ -79,7 +79,7 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) {
if arg_type == abi_type.value_type { if arg_type == abi_type.value_type {
// No value translation is necessary, this argument matches the ABI type. // No value translation is necessary, this argument matches the ABI type.
// Just use the original EBB argument value. This is the most common case. // Just use the original EBB argument value. This is the most common case.
pos.func.dfg.attach_ebb_arg(entry, arg); pos.func.dfg.attach_ebb_param(entry, arg);
match abi_type.purpose { match abi_type.purpose {
ArgumentPurpose::Normal => {} ArgumentPurpose::Normal => {}
ArgumentPurpose::StructReturn => { ArgumentPurpose::StructReturn => {
@@ -108,7 +108,7 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) {
); );
if ty == abi_type.value_type { if ty == abi_type.value_type {
abi_arg += 1; abi_arg += 1;
Ok(func.dfg.append_ebb_arg(entry, ty)) Ok(func.dfg.append_ebb_param(entry, ty))
} else { } else {
Err(abi_type) Err(abi_type)
} }
@@ -155,7 +155,7 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) {
// Just create entry block values to match here. We will use them in `handle_return_abi()` // Just create entry block values to match here. We will use them in `handle_return_abi()`
// below. // below.
pos.func.dfg.append_ebb_arg(entry, arg.value_type); pos.func.dfg.append_ebb_param(entry, arg.value_type);
} }
} }
@@ -584,7 +584,7 @@ pub fn handle_return_abi(inst: Inst, func: &mut Function, cfg: &ControlFlowGraph
.expect("No matching special purpose argument."); .expect("No matching special purpose argument.");
// Get the corresponding entry block value and add it to the return instruction's // Get the corresponding entry block value and add it to the return instruction's
// arguments. // arguments.
let val = pos.func.dfg.ebb_args( let val = pos.func.dfg.ebb_params(
pos.func.layout.entry_block().unwrap(), pos.func.layout.entry_block().unwrap(),
) )
[idx]; [idx];
@@ -611,7 +611,9 @@ pub fn handle_return_abi(inst: Inst, func: &mut Function, cfg: &ControlFlowGraph
/// stack slot already during legalization. /// stack slot already during legalization.
fn spill_entry_arguments(func: &mut Function, entry: Ebb) { fn spill_entry_arguments(func: &mut Function, entry: Ebb) {
for (abi, &arg) in func.signature.argument_types.iter().zip( for (abi, &arg) in func.signature.argument_types.iter().zip(
func.dfg.ebb_args(entry), func.dfg.ebb_params(
entry,
),
) )
{ {
if let ArgumentLoc::Stack(offset) = abi.location { if let ArgumentLoc::Stack(offset) = abi.location {

View File

@@ -26,19 +26,10 @@ pub fn expand_global_addr(inst: ir::Inst, func: &mut ir::Function, _cfg: &mut Co
/// Expand a `global_addr` instruction for a vmctx global. /// Expand a `global_addr` instruction for a vmctx global.
fn vmctx_addr(inst: ir::Inst, func: &mut ir::Function, offset: i64) { fn vmctx_addr(inst: ir::Inst, func: &mut ir::Function, offset: i64) {
// Find the incoming `vmctx` function argument. Start searching from the back since the special
// arguments are appended by signature legalization.
//
// This argument must exist; `vmctx` global variables can not be used in functions with calling
// conventions that don't add a `vmctx` argument.
let argidx = func.signature
.argument_types
.iter()
.rposition(|abi| abi.purpose == ir::ArgumentPurpose::VMContext)
.expect("Need vmctx argument for vmctx global");
// Get the value representing the `vmctx` argument. // Get the value representing the `vmctx` argument.
let vmctx = func.dfg.ebb_args(func.layout.entry_block().unwrap())[argidx]; let vmctx = func.special_arg(ir::ArgumentPurpose::VMContext).expect(
"Missing vmctx parameter",
);
// Simply replace the `global_addr` instruction with an `iadd_imm`, reusing the result value. // Simply replace the `global_addr` instruction with an `iadd_imm`, reusing the result value.
func.dfg.replace(inst).iadd_imm(vmctx, offset); func.dfg.replace(inst).iadd_imm(vmctx, offset);

View File

@@ -201,7 +201,7 @@ fn expand_select(inst: ir::Inst, func: &mut ir::Function, cfg: &mut ControlFlowG
let result = func.dfg.first_result(inst); let result = func.dfg.first_result(inst);
func.dfg.clear_results(inst); func.dfg.clear_results(inst);
let new_ebb = func.dfg.make_ebb(); let new_ebb = func.dfg.make_ebb();
func.dfg.attach_ebb_arg(new_ebb, result); func.dfg.attach_ebb_param(new_ebb, result);
func.dfg.replace(inst).brnz(ctrl, new_ebb, &[tval]); func.dfg.replace(inst).brnz(ctrl, new_ebb, &[tval]);
let mut pos = FuncCursor::new(func).after_inst(inst); let mut pos = FuncCursor::new(func).after_inst(inst);

View File

@@ -194,7 +194,7 @@ fn split_value(
let mut reuse = None; let mut reuse = None;
match pos.func.dfg.value_def(value) { match pos.func.dfg.value_def(value) {
ValueDef::Res(inst, num) => { ValueDef::Result(inst, num) => {
// This is an instruction result. See if the value was created by a `concat` // This is an instruction result. See if the value was created by a `concat`
// instruction. // instruction.
if let InstructionData::Binary { opcode, args, .. } = pos.func.dfg[inst] { if let InstructionData::Binary { opcode, args, .. } = pos.func.dfg[inst] {
@@ -204,11 +204,11 @@ fn split_value(
} }
} }
} }
ValueDef::Arg(ebb, num) => { ValueDef::Param(ebb, num) => {
// This is an EBB argument. We can split the argument value unless this is the entry // This is an EBB parameter. We can split the parameter value unless this is the entry
// block. // block.
if pos.func.layout.entry_block() != Some(ebb) { if pos.func.layout.entry_block() != Some(ebb) {
// We are going to replace the argument at `num` with two new arguments. // We are going to replace the parameter at `num` with two new arguments.
// Determine the new value types. // Determine the new value types.
let ty = pos.func.dfg.value_type(value); let ty = pos.func.dfg.value_type(value);
let split_type = match concat { let split_type = match concat {
@@ -217,20 +217,20 @@ fn split_value(
_ => panic!("Unhandled concat opcode: {}", concat), _ => panic!("Unhandled concat opcode: {}", concat),
}; };
// Since the `repairs` stack potentially contains other argument numbers for `ebb`, // Since the `repairs` stack potentially contains other parameter numbers for
// avoid shifting and renumbering EBB arguments. It could invalidate other // `ebb`, avoid shifting and renumbering EBB parameters. It could invalidate other
// `repairs` entries. // `repairs` entries.
// //
// Replace the original `value` with the low part, and append the high part at the // Replace the original `value` with the low part, and append the high part at the
// end of the argument list. // end of the argument list.
let lo = pos.func.dfg.replace_ebb_arg(value, split_type); let lo = pos.func.dfg.replace_ebb_param(value, split_type);
let hi_num = pos.func.dfg.num_ebb_args(ebb); let hi_num = pos.func.dfg.num_ebb_params(ebb);
let hi = pos.func.dfg.append_ebb_arg(ebb, split_type); let hi = pos.func.dfg.append_ebb_param(ebb, split_type);
reuse = Some((lo, hi)); reuse = Some((lo, hi));
// Now the original value is dangling. Insert a concatenation instruction that can // Now the original value is dangling. Insert a concatenation instruction that can
// compute it from the two new arguments. This also serves as a record of what we // compute it from the two new parameters. This also serves as a record of what we
// did so a future call to this function doesn't have to redo the work. // did so a future call to this function doesn't have to redo the work.
// //
// Note that it is safe to move `pos` here since `reuse` was set above, so we don't // Note that it is safe to move `pos` here since `reuse` was set above, so we don't
@@ -243,7 +243,7 @@ fn split_value(
hi, hi,
); );
// Finally, splitting the EBB argument is not enough. We also have to repair all // Finally, splitting the EBB parameter is not enough. We also have to repair all
// of the predecessor instructions that branch here. // of the predecessor instructions that branch here.
add_repair(concat, split_type, ebb, num, hi_num, repairs); add_repair(concat, split_type, ebb, num, hi_num, repairs);
} }
@@ -299,7 +299,7 @@ fn resolve_splits(dfg: &ir::DataFlowGraph, value: Value) -> Value {
let split_res; let split_res;
let concat_opc; let concat_opc;
let split_arg; let split_arg;
if let ValueDef::Res(inst, num) = dfg.value_def(value) { if let ValueDef::Result(inst, num) = dfg.value_def(value) {
split_res = num; split_res = num;
concat_opc = match dfg[inst].opcode() { concat_opc = match dfg[inst].opcode() {
Opcode::Isplit => Opcode::Iconcat, Opcode::Isplit => Opcode::Iconcat,
@@ -312,7 +312,7 @@ fn resolve_splits(dfg: &ir::DataFlowGraph, value: Value) -> Value {
} }
// See if split_arg is defined by a concatenation instruction. // See if split_arg is defined by a concatenation instruction.
if let ValueDef::Res(inst, _) = dfg.value_def(split_arg) { if let ValueDef::Result(inst, _) = dfg.value_def(split_arg) {
if dfg[inst].opcode() == concat_opc { if dfg[inst].opcode() == concat_opc {
return dfg.inst_args(inst)[split_res]; return dfg.inst_args(inst)[split_res];
} }

View File

@@ -63,7 +63,7 @@ fn create_pre_header(
domtree: &DominatorTree, domtree: &DominatorTree,
) -> Ebb { ) -> Ebb {
let pool = &mut ListPool::<Value>::new(); let pool = &mut ListPool::<Value>::new();
let header_args_values: Vec<Value> = func.dfg.ebb_args(header).into_iter().cloned().collect(); let header_args_values: Vec<Value> = func.dfg.ebb_params(header).into_iter().cloned().collect();
let header_args_types: Vec<Type> = header_args_values let header_args_types: Vec<Type> = header_args_values
.clone() .clone()
.into_iter() .into_iter()
@@ -72,7 +72,7 @@ fn create_pre_header(
let pre_header = func.dfg.make_ebb(); let pre_header = func.dfg.make_ebb();
let mut pre_header_args_value: EntityList<Value> = EntityList::new(); let mut pre_header_args_value: EntityList<Value> = EntityList::new();
for typ in header_args_types { for typ in header_args_types {
pre_header_args_value.push(func.dfg.append_ebb_arg(pre_header, typ), pool); pre_header_args_value.push(func.dfg.append_ebb_param(pre_header, typ), pool);
} }
for &(_, last_inst) in cfg.get_predecessors(header) { for &(_, last_inst) in cfg.get_predecessors(header) {
// We only follow normal edges (not the back edges) // We only follow normal edges (not the back edges)
@@ -143,7 +143,7 @@ fn remove_loop_invariant_instructions(
// We traverse the loop EBB in reverse post-order. // We traverse the loop EBB in reverse post-order.
for ebb in postorder_ebbs_loop(loop_analysis, cfg, lp).iter().rev() { for ebb in postorder_ebbs_loop(loop_analysis, cfg, lp).iter().rev() {
// Arguments of the EBB are loop values // Arguments of the EBB are loop values
for val in pos.func.dfg.ebb_args(*ebb) { for val in pos.func.dfg.ebb_params(*ebb) {
loop_values.insert(*val); loop_values.insert(*val);
} }
pos.goto_top(*ebb); pos.goto_top(*ebb);

View File

@@ -236,7 +236,7 @@ mod test {
let ebb1 = func.dfg.make_ebb(); let ebb1 = func.dfg.make_ebb();
let ebb2 = func.dfg.make_ebb(); let ebb2 = func.dfg.make_ebb();
let ebb3 = func.dfg.make_ebb(); let ebb3 = func.dfg.make_ebb();
let cond = func.dfg.append_ebb_arg(ebb0, types::I32); let cond = func.dfg.append_ebb_param(ebb0, types::I32);
{ {
let mut cur = FuncCursor::new(&mut func); let mut cur = FuncCursor::new(&mut func);
@@ -288,7 +288,7 @@ mod test {
let ebb3 = func.dfg.make_ebb(); let ebb3 = func.dfg.make_ebb();
let ebb4 = func.dfg.make_ebb(); let ebb4 = func.dfg.make_ebb();
let ebb5 = func.dfg.make_ebb(); let ebb5 = func.dfg.make_ebb();
let cond = func.dfg.append_ebb_arg(ebb0, types::I32); let cond = func.dfg.append_ebb_param(ebb0, types::I32);
{ {
let mut cur = FuncCursor::new(&mut func); let mut cur = FuncCursor::new(&mut func);

View File

@@ -2,8 +2,8 @@
//! //!
//! Conventional SSA form is a subset of SSA form where any (transitively) phi-related values do //! Conventional SSA form is a subset of SSA form where any (transitively) phi-related values do
//! not interfere. We construct CSSA by building virtual registers that are as large as possible //! not interfere. We construct CSSA by building virtual registers that are as large as possible
//! and inserting copies where necessary such that all values passed to an EBB argument will belong //! and inserting copies where necessary such that all argument values passed to an EBB parameter
//! to the same virtual register as the EBB argument value itself. //! will belong to the same virtual register as the EBB parameter value itself.
use cursor::{Cursor, EncCursor}; use cursor::{Cursor, EncCursor};
use dbg::DisplayList; use dbg::DisplayList;
@@ -289,8 +289,8 @@ impl Coalescing {
for &ebb in domtree.cfg_postorder() { for &ebb in domtree.cfg_postorder() {
let preds = cfg.get_predecessors(ebb); let preds = cfg.get_predecessors(ebb);
if !preds.is_empty() { if !preds.is_empty() {
for argnum in 0..context.func.dfg.num_ebb_args(ebb) { for argnum in 0..context.func.dfg.num_ebb_params(ebb) {
context.coalesce_ebb_arg(ebb, argnum, preds) context.coalesce_ebb_param(ebb, argnum, preds)
} }
} }
} }
@@ -298,10 +298,10 @@ impl Coalescing {
} }
impl<'a> Context<'a> { impl<'a> Context<'a> {
/// Coalesce the `argnum`'th argument to `ebb`. /// Coalesce the `argnum`'th parameter on `ebb`.
fn coalesce_ebb_arg(&mut self, ebb: Ebb, argnum: usize, preds: &[BasicBlock]) { fn coalesce_ebb_param(&mut self, ebb: Ebb, argnum: usize, preds: &[BasicBlock]) {
self.split_values.clear(); self.split_values.clear();
let mut succ_val = self.func.dfg.ebb_args(ebb)[argnum]; let mut succ_val = self.func.dfg.ebb_params(ebb)[argnum];
dbg!("Processing {}/{}: {}", ebb, argnum, succ_val); dbg!("Processing {}/{}: {}", ebb, argnum, succ_val);
// We want to merge the virtual register for `succ_val` with the virtual registers for // We want to merge the virtual register for `succ_val` with the virtual registers for
@@ -421,7 +421,7 @@ impl<'a> Context<'a> {
// Never coalesce incoming function arguments on the stack. These arguments are // Never coalesce incoming function arguments on the stack. These arguments are
// pre-spilled, and the rest of the virtual register would be forced to spill to the // pre-spilled, and the rest of the virtual register would be forced to spill to the
// `incoming_arg` stack slot too. // `incoming_arg` stack slot too.
if let ValueDef::Arg(def_ebb, def_num) = self.func.dfg.value_def(pred_val) { if let ValueDef::Param(def_ebb, def_num) = self.func.dfg.value_def(pred_val) {
if Some(def_ebb) == self.func.layout.entry_block() && if Some(def_ebb) == self.func.layout.entry_block() &&
self.func.signature.argument_types[def_num] self.func.signature.argument_types[def_num]
.location .location
@@ -530,7 +530,7 @@ impl<'a> Context<'a> {
/// Split the congruence class for the successor EBB value itself. /// Split the congruence class for the successor EBB value itself.
fn split_succ(&mut self, ebb: Ebb, succ_val: Value) -> Value { fn split_succ(&mut self, ebb: Ebb, succ_val: Value) -> Value {
let ty = self.func.dfg.value_type(succ_val); let ty = self.func.dfg.value_type(succ_val);
let new_val = self.func.dfg.replace_ebb_arg(succ_val, ty); let new_val = self.func.dfg.replace_ebb_param(succ_val, ty);
// Insert a copy instruction at the top of ebb. // Insert a copy instruction at the top of ebb.
let mut pos = EncCursor::new(self.func, self.isa).at_first_inst(ebb); let mut pos = EncCursor::new(self.func, self.isa).at_first_inst(ebb);

View File

@@ -409,7 +409,7 @@ impl<'a> Context<'a> {
// If this is the first time we branch to `dest`, color its arguments to match the current // If this is the first time we branch to `dest`, color its arguments to match the current
// register state. // register state.
if let Some(dest) = color_dest_args { if let Some(dest) = color_dest_args {
self.color_ebb_arguments(inst, dest); self.color_ebb_params(inst, dest);
} }
// Apply the solution to the defs. // Apply the solution to the defs.
@@ -556,7 +556,7 @@ impl<'a> Context<'a> {
// Now handle the EBB arguments. // Now handle the EBB arguments.
let br_args = self.cur.func.dfg.inst_variable_args(inst); let br_args = self.cur.func.dfg.inst_variable_args(inst);
let dest_args = self.cur.func.dfg.ebb_args(dest); let dest_args = self.cur.func.dfg.ebb_params(dest);
assert_eq!(br_args.len(), dest_args.len()); assert_eq!(br_args.len(), dest_args.len());
for (&dest_arg, &br_arg) in dest_args.iter().zip(br_args) { for (&dest_arg, &br_arg) in dest_args.iter().zip(br_args) {
// The first time we encounter a branch to `dest`, we get to pick the location. The // The first time we encounter a branch to `dest`, we get to pick the location. The
@@ -565,7 +565,7 @@ impl<'a> Context<'a> {
ValueLoc::Unassigned => { ValueLoc::Unassigned => {
// This is the first branch to `dest`, so we should color `dest_arg` instead of // This is the first branch to `dest`, so we should color `dest_arg` instead of
// `br_arg`. However, we don't know where `br_arg` will end up until // `br_arg`. However, we don't know where `br_arg` will end up until
// after `shuffle_inputs`. See `color_ebb_arguments` below. // after `shuffle_inputs`. See `color_ebb_params` below.
// //
// It is possible for `dest_arg` to have no affinity, and then it should simply // It is possible for `dest_arg` to have no affinity, and then it should simply
// be ignored. // be ignored.
@@ -595,13 +595,13 @@ impl<'a> Context<'a> {
false false
} }
/// Knowing that we've never seen a branch to `dest` before, color its arguments to match our /// Knowing that we've never seen a branch to `dest` before, color its parameters to match our
/// register state. /// register state.
/// ///
/// This function is only called when `program_ebb_arguments()` returned `true`. /// This function is only called when `program_ebb_arguments()` returned `true`.
fn color_ebb_arguments(&mut self, inst: Inst, dest: Ebb) { fn color_ebb_params(&mut self, inst: Inst, dest: Ebb) {
let br_args = self.cur.func.dfg.inst_variable_args(inst); let br_args = self.cur.func.dfg.inst_variable_args(inst);
let dest_args = self.cur.func.dfg.ebb_args(dest); let dest_args = self.cur.func.dfg.ebb_params(dest);
assert_eq!(br_args.len(), dest_args.len()); assert_eq!(br_args.len(), dest_args.len());
for (&dest_arg, &br_arg) in dest_args.iter().zip(br_args) { for (&dest_arg, &br_arg) in dest_args.iter().zip(br_args) {
match self.cur.func.locations[dest_arg] { match self.cur.func.locations[dest_arg] {
@@ -914,7 +914,7 @@ impl<'a> Context<'a> {
} }
} }
/// Replace all global values define by `inst` with local values that are then copied into the /// Replace all global values defined by `inst` with local values that are then copied into the
/// global value: /// global value:
/// ///
/// v1 = foo /// v1 = foo
@@ -938,7 +938,7 @@ impl<'a> Context<'a> {
for lv in tracker.live_mut().iter_mut().rev() { for lv in tracker.live_mut().iter_mut().rev() {
// Keep going until we reach a value that is not defined by `inst`. // Keep going until we reach a value that is not defined by `inst`.
if match self.cur.func.dfg.value_def(lv.value) { if match self.cur.func.dfg.value_def(lv.value) {
ValueDef::Res(i, _) => i != inst, ValueDef::Result(i, _) => i != inst,
_ => true, _ => true,
} }
{ {

View File

@@ -202,24 +202,22 @@ impl LiveValueTracker {
} }
} }
// Now add all the live arguments to `ebb`. // Now add all the live parameters to `ebb`.
let first_arg = self.live.values.len(); let first_arg = self.live.values.len();
for &value in dfg.ebb_args(ebb) { for &value in dfg.ebb_params(ebb) {
let lr = liveness.get(value).expect( let lr = &liveness[value];
"EBB argument value has no live range",
);
assert_eq!(lr.def(), ebb.into()); assert_eq!(lr.def(), ebb.into());
match lr.def_local_end().into() { match lr.def_local_end().into() {
ExpandedProgramPoint::Inst(endpoint) => { ExpandedProgramPoint::Inst(endpoint) => {
self.live.push(value, endpoint, lr); self.live.push(value, endpoint, lr);
} }
ExpandedProgramPoint::Ebb(local_ebb) => { ExpandedProgramPoint::Ebb(local_ebb) => {
// This is a dead EBB argument which is not even live into the first // This is a dead EBB parameter which is not even live into the first
// instruction in the EBB. // instruction in the EBB.
assert_eq!( assert_eq!(
local_ebb, local_ebb,
ebb, ebb,
"EBB argument live range ends at wrong EBB header" "EBB parameter live range ends at wrong EBB header"
); );
// Give this value a fake endpoint that is the first instruction in the EBB. // Give this value a fake endpoint that is the first instruction in the EBB.
// We expect it to be removed by calling `drop_dead_args()`. // We expect it to be removed by calling `drop_dead_args()`.

View File

@@ -205,7 +205,7 @@ fn get_or_create<'a>(
let def; let def;
let affinity; let affinity;
match func.dfg.value_def(value) { match func.dfg.value_def(value) {
ValueDef::Res(inst, rnum) => { ValueDef::Result(inst, rnum) => {
def = inst.into(); def = inst.into();
// Initialize the affinity from the defining instruction's result constraints. // Initialize the affinity from the defining instruction's result constraints.
// Don't do this for call return values which are always tied to a single register. // Don't do this for call return values which are always tied to a single register.
@@ -221,14 +221,14 @@ fn get_or_create<'a>(
}) })
.unwrap_or_default(); .unwrap_or_default();
} }
ValueDef::Arg(ebb, num) => { ValueDef::Param(ebb, num) => {
def = ebb.into(); def = ebb.into();
if func.layout.entry_block() == Some(ebb) { if func.layout.entry_block() == Some(ebb) {
// The affinity for entry block arguments can be inferred from the function // The affinity for entry block parameters can be inferred from the function
// signature. // signature.
affinity = Affinity::abi(&func.signature.argument_types[num], isa); affinity = Affinity::abi(&func.signature.argument_types[num], isa);
} else { } else {
// Don't apply any affinity to normal EBB arguments. // Don't apply any affinity to normal EBB parameters.
// They could be in a register or on the stack. // They could be in a register or on the stack.
affinity = Default::default(); affinity = Default::default();
} }
@@ -290,8 +290,8 @@ pub struct Liveness {
/// It lives here to avoid repeated allocation of scratch memory. /// It lives here to avoid repeated allocation of scratch memory.
worklist: Vec<Ebb>, worklist: Vec<Ebb>,
/// Working space for the `propagate_ebb_arguments` algorithm. /// Working space for the `propagate_ebb_params` algorithm.
ebb_args: Vec<Value>, ebb_params: Vec<Value>,
} }
impl Liveness { impl Liveness {
@@ -303,7 +303,7 @@ impl Liveness {
Liveness { Liveness {
ranges: LiveRangeSet::new(), ranges: LiveRangeSet::new(),
worklist: Vec::new(), worklist: Vec::new(),
ebb_args: Vec::new(), ebb_params: Vec::new(),
} }
} }
@@ -378,10 +378,10 @@ impl Liveness {
// elimination pass if we visit a post-order of the dominator tree? // elimination pass if we visit a post-order of the dominator tree?
// TODO: Resolve value aliases while we're visiting instructions? // TODO: Resolve value aliases while we're visiting instructions?
for ebb in func.layout.ebbs() { for ebb in func.layout.ebbs() {
// Make sure we have created live ranges for dead EBB arguments. // Make sure we have created live ranges for dead EBB parameters.
// TODO: If these arguments are really dead, we could remove them, except for the entry // TODO: If these parameters are really dead, we could remove them, except for the
// block which must match the function signature. // entry block which must match the function signature.
for &arg in func.dfg.ebb_args(ebb) { for &arg in func.dfg.ebb_params(ebb) {
get_or_create(&mut self.ranges, arg, isa, func, &enc_info); get_or_create(&mut self.ranges, arg, isa, func, &enc_info);
} }
@@ -431,28 +431,28 @@ impl Liveness {
} }
} }
self.propagate_ebb_arguments(func, cfg); self.propagate_ebb_params(func, cfg);
} }
/// Propagate affinities for EBB arguments. /// Propagate affinities for EBB parameters.
/// ///
/// If an EBB argument value has an affinity, all predecessors must pass a value with an /// If an EBB argument value has an affinity, all predecessors must pass a value with an
/// affinity. /// affinity.
pub fn propagate_ebb_arguments(&mut self, func: &Function, cfg: &ControlFlowGraph) { pub fn propagate_ebb_params(&mut self, func: &Function, cfg: &ControlFlowGraph) {
assert!(self.ebb_args.is_empty()); assert!(self.ebb_params.is_empty());
for ebb in func.layout.ebbs() { for ebb in func.layout.ebbs() {
for &arg in func.dfg.ebb_args(ebb) { for &arg in func.dfg.ebb_params(ebb) {
let affinity = self.ranges.get(arg).unwrap().affinity; let affinity = self.ranges.get(arg).unwrap().affinity;
if affinity.is_none() { if affinity.is_none() {
continue; continue;
} }
self.ebb_args.push(arg); self.ebb_params.push(arg);
// Now apply the affinity to all predecessors recursively. // Now apply the affinity to all predecessors recursively.
while let Some(succ_arg) = self.ebb_args.pop() { while let Some(succ_arg) = self.ebb_params.pop() {
let (succ_ebb, num) = match func.dfg.value_def(succ_arg) { let (succ_ebb, num) = match func.dfg.value_def(succ_arg) {
ValueDef::Arg(e, n) => (e, n), ValueDef::Param(e, n) => (e, n),
_ => continue, _ => continue,
}; };
@@ -461,7 +461,7 @@ impl Liveness {
let pred_affinity = &mut self.ranges.get_mut(pred_arg).unwrap().affinity; let pred_affinity = &mut self.ranges.get_mut(pred_arg).unwrap().affinity;
if pred_affinity.is_none() { if pred_affinity.is_none() {
*pred_affinity = affinity; *pred_affinity = affinity;
self.ebb_args.push(pred_arg); self.ebb_params.push(pred_arg);
} }
} }
} }

View File

@@ -139,7 +139,7 @@ impl<'a> Context<'a> {
assert_eq!(liveins.len(), 0); assert_eq!(liveins.len(), 0);
self.visit_entry_args(ebb, args); self.visit_entry_args(ebb, args);
} else { } else {
self.visit_ebb_args(ebb, args); self.visit_ebb_params(ebb, args);
} }
} }
@@ -156,7 +156,10 @@ impl<'a> Context<'a> {
if arg.affinity.is_stack() { if arg.affinity.is_stack() {
// An incoming register parameter was spilled. Replace the parameter value // An incoming register parameter was spilled. Replace the parameter value
// with a temporary register value that is immediately spilled. // with a temporary register value that is immediately spilled.
let reg = self.cur.func.dfg.replace_ebb_arg(arg.value, abi.value_type); let reg = self.cur.func.dfg.replace_ebb_param(
arg.value,
abi.value_type,
);
let affinity = Affinity::abi(&abi, self.cur.isa); let affinity = Affinity::abi(&abi, self.cur.isa);
self.liveness.create_dead(reg, ebb, affinity); self.liveness.create_dead(reg, ebb, affinity);
self.insert_spill(ebb, arg.value, reg); self.insert_spill(ebb, arg.value, reg);
@@ -170,7 +173,7 @@ impl<'a> Context<'a> {
} }
} }
fn visit_ebb_args(&mut self, ebb: Ebb, _args: &[LiveValue]) { fn visit_ebb_params(&mut self, ebb: Ebb, _args: &[LiveValue]) {
self.cur.goto_first_inst(ebb); self.cur.goto_first_inst(ebb);
} }

View File

@@ -101,22 +101,22 @@ impl<'a> CssaVerifier<'a> {
fn check_cssa(&self) -> Result { fn check_cssa(&self) -> Result {
for ebb in self.func.layout.ebbs() { for ebb in self.func.layout.ebbs() {
let ebb_args = self.func.dfg.ebb_args(ebb); let ebb_params = self.func.dfg.ebb_params(ebb);
for &(_, pred) in self.cfg.get_predecessors(ebb) { for &(_, pred) in self.cfg.get_predecessors(ebb) {
let pred_args = self.func.dfg.inst_variable_args(pred); let pred_args = self.func.dfg.inst_variable_args(pred);
// This should have been caught by an earlier verifier pass. // This should have been caught by an earlier verifier pass.
assert_eq!( assert_eq!(
ebb_args.len(), ebb_params.len(),
pred_args.len(), pred_args.len(),
"Wrong arguments on branch." "Wrong arguments on branch."
); );
for (&ebb_arg, &pred_arg) in ebb_args.iter().zip(pred_args) { for (&ebb_param, &pred_arg) in ebb_params.iter().zip(pred_args) {
if !self.virtregs.same_class(ebb_arg, pred_arg) { if !self.virtregs.same_class(ebb_param, pred_arg) {
return err!( return err!(
pred, pred,
"{} and {} must be in the same virtual register", "{} and {} must be in the same virtual register",
ebb_arg, ebb_param,
pred_arg pred_arg
); );
} }

View File

@@ -49,7 +49,7 @@ impl<'a> LivenessVerifier<'a> {
/// Check all EBB arguments. /// Check all EBB arguments.
fn check_ebbs(&self) -> Result { fn check_ebbs(&self) -> Result {
for ebb in self.func.layout.ebbs() { for ebb in self.func.layout.ebbs() {
for &val in self.func.dfg.ebb_args(ebb) { for &val in self.func.dfg.ebb_params(ebb) {
let lr = match self.liveness.get(val) { let lr = match self.liveness.get(val) {
Some(lr) => lr, Some(lr) => lr,
None => return err!(ebb, "EBB arg {} has no live range", val), None => return err!(ebb, "EBB arg {} has no live range", val),
@@ -164,7 +164,7 @@ impl<'a> LivenessVerifier<'a> {
// branch argument. // branch argument.
self.func self.func
.dfg .dfg
.ebb_args(dest) .ebb_params(dest)
.get(argnum - fixed_args) .get(argnum - fixed_args)
.and_then(|&v| self.liveness.get(v)) .and_then(|&v| self.liveness.get(v))
.map(|lr| lr.affinity.is_none()) .map(|lr| lr.affinity.is_none())

View File

@@ -7,7 +7,7 @@
//! the EBB as reported by `inst_ebb()`. //! the EBB as reported by `inst_ebb()`.
//! - Every EBB must end in a terminator instruction, and no other instruction //! - Every EBB must end in a terminator instruction, and no other instruction
//! can be a terminator. //! can be a terminator.
//! - Every value in the `ebb_args` iterator belongs to the EBB as reported by `value_ebb`. //! - Every value in the `ebb_params` iterator belongs to the EBB as reported by `value_ebb`.
//! //!
//! Instruction integrity //! Instruction integrity
//! //!
@@ -212,10 +212,10 @@ impl<'a> Verifier<'a> {
return err!(inst, "should belong to {} not {:?}", ebb, inst_ebb); return err!(inst, "should belong to {} not {:?}", ebb, inst_ebb);
} }
// Arguments belong to the correct ebb. // Parameters belong to the correct ebb.
for &arg in self.func.dfg.ebb_args(ebb) { for &arg in self.func.dfg.ebb_params(ebb) {
match self.func.dfg.value_def(arg) { match self.func.dfg.value_def(arg) {
ValueDef::Arg(arg_ebb, _) => { ValueDef::Param(arg_ebb, _) => {
if ebb != arg_ebb { if ebb != arg_ebb {
return err!(arg, "does not belong to {}", ebb); return err!(arg, "does not belong to {}", ebb);
} }
@@ -441,7 +441,7 @@ impl<'a> Verifier<'a> {
// SSA form // SSA form
match dfg.value_def(v) { match dfg.value_def(v) {
ValueDef::Res(def_inst, _) => { ValueDef::Result(def_inst, _) => {
// Value is defined by an instruction that exists. // Value is defined by an instruction that exists.
if !dfg.inst_is_valid(def_inst) { if !dfg.inst_is_valid(def_inst) {
return err!( return err!(
@@ -471,7 +471,7 @@ impl<'a> Verifier<'a> {
return err!(loc_inst, "uses value from non-dominating {}", def_inst); return err!(loc_inst, "uses value from non-dominating {}", def_inst);
} }
} }
ValueDef::Arg(ebb, _) => { ValueDef::Param(ebb, _) => {
// Value is defined by an existing EBB. // Value is defined by an existing EBB.
if !dfg.ebb_is_valid(ebb) { if !dfg.ebb_is_valid(ebb) {
return err!(loc_inst, "{} is defined by invalid EBB {}", v, ebb); return err!(loc_inst, "{} is defined by invalid EBB {}", v, ebb);
@@ -554,18 +554,23 @@ impl<'a> Verifier<'a> {
fn typecheck_entry_block_arguments(&self) -> Result { fn typecheck_entry_block_arguments(&self) -> Result {
if let Some(ebb) = self.func.layout.entry_block() { if let Some(ebb) = self.func.layout.entry_block() {
let expected_types = &self.func.signature.argument_types; let expected_types = &self.func.signature.argument_types;
let ebb_arg_count = self.func.dfg.num_ebb_args(ebb); let ebb_param_count = self.func.dfg.num_ebb_params(ebb);
if ebb_arg_count != expected_types.len() { if ebb_param_count != expected_types.len() {
return err!(ebb, "entry block arguments must match function signature"); return err!(
ebb,
"entry block parameters ({}) must match function signature ({})",
ebb_param_count,
expected_types.len()
);
} }
for (i, &arg) in self.func.dfg.ebb_args(ebb).iter().enumerate() { for (i, &arg) in self.func.dfg.ebb_params(ebb).iter().enumerate() {
let arg_type = self.func.dfg.value_type(arg); let arg_type = self.func.dfg.value_type(arg);
if arg_type != expected_types[i].value_type { if arg_type != expected_types[i].value_type {
return err!( return err!(
ebb, ebb,
"entry block argument {} expected to have type {}, got {}", "entry block parameter {} expected to have type {}, got {}",
i, i,
expected_types[i], expected_types[i],
arg_type arg_type
@@ -671,14 +676,14 @@ impl<'a> Verifier<'a> {
fn typecheck_variable_args(&self, inst: Inst) -> Result { fn typecheck_variable_args(&self, inst: Inst) -> Result {
match self.func.dfg[inst].analyze_branch(&self.func.dfg.value_lists) { match self.func.dfg[inst].analyze_branch(&self.func.dfg.value_lists) {
BranchInfo::SingleDest(ebb, _) => { BranchInfo::SingleDest(ebb, _) => {
let iter = self.func.dfg.ebb_args(ebb).iter().map(|&v| { let iter = self.func.dfg.ebb_params(ebb).iter().map(|&v| {
self.func.dfg.value_type(v) self.func.dfg.value_type(v)
}); });
self.typecheck_variable_args_iterator(inst, iter)?; self.typecheck_variable_args_iterator(inst, iter)?;
} }
BranchInfo::Table(table) => { BranchInfo::Table(table) => {
for (_, ebb) in self.func.jump_tables[table].entries() { for (_, ebb) in self.func.jump_tables[table].entries() {
let arg_count = self.func.dfg.num_ebb_args(ebb); let arg_count = self.func.dfg.num_ebb_params(ebb);
if arg_count != 0 { if arg_count != 0 {
return err!( return err!(
inst, inst,

View File

@@ -121,7 +121,7 @@ pub fn write_ebb_header(
let regs = isa.map(TargetIsa::register_info); let regs = isa.map(TargetIsa::register_info);
let regs = regs.as_ref(); let regs = regs.as_ref();
let mut args = func.dfg.ebb_args(ebb).iter().cloned(); let mut args = func.dfg.ebb_params(ebb).iter().cloned();
match args.next() { match args.next() {
None => return writeln!(w, ":"), None => return writeln!(w, ":"),
Some(arg) => { Some(arg) => {
@@ -177,8 +177,8 @@ fn type_suffix(func: &Function, inst: Inst) -> Option<Type> {
if constraints.use_typevar_operand() { if constraints.use_typevar_operand() {
let ctrl_var = inst_data.typevar_operand(&func.dfg.value_lists).unwrap(); let ctrl_var = inst_data.typevar_operand(&func.dfg.value_lists).unwrap();
let def_ebb = match func.dfg.value_def(ctrl_var) { let def_ebb = match func.dfg.value_def(ctrl_var) {
ValueDef::Res(instr, _) => func.layout.inst_ebb(instr), ValueDef::Result(instr, _) => func.layout.inst_ebb(instr),
ValueDef::Arg(ebb, _) => Some(ebb), ValueDef::Param(ebb, _) => Some(ebb),
}; };
if def_ebb.is_some() && def_ebb == func.layout.inst_ebb(inst) { if def_ebb.is_some() && def_ebb == func.layout.inst_ebb(inst) {
return None; return None;
@@ -465,13 +465,13 @@ mod tests {
"function %foo() native {\n ss0 = local 4\n\nebb0:\n}\n" "function %foo() native {\n ss0 = local 4\n\nebb0:\n}\n"
); );
f.dfg.append_ebb_arg(ebb, types::I8); f.dfg.append_ebb_param(ebb, types::I8);
assert_eq!( assert_eq!(
f.to_string(), f.to_string(),
"function %foo() native {\n ss0 = local 4\n\nebb0(v0: i8):\n}\n" "function %foo() native {\n ss0 = local 4\n\nebb0(v0: i8):\n}\n"
); );
f.dfg.append_ebb_arg(ebb, types::F32.by(4).unwrap()); f.dfg.append_ebb_param(ebb, types::F32.by(4).unwrap());
assert_eq!( assert_eq!(
f.to_string(), f.to_string(),
"function %foo() native {\n ss0 = local 4\n\nebb0(v0: i8, v1: f32x4):\n}\n" "function %foo() native {\n ss0 = local 4\n\nebb0(v0: i8, v1: f32x4):\n}\n"

View File

@@ -136,7 +136,7 @@ impl<'short, 'long, Variable> InstBuilderBase<'short> for FuncInstBuilder<'short
} }
_ => panic!("should not happen"), _ => panic!("should not happen"),
}; };
self.builder.ebb_args_adjustment(dest_ebb, &args_types); self.builder.ebb_params_adjustment(dest_ebb, &args_types);
self.builder.declare_successor(dest_ebb, inst); self.builder.declare_successor(dest_ebb, inst);
} }
None => { None => {
@@ -273,8 +273,8 @@ where
let basic_block = self.builder.ssa.header_block(ebb); let basic_block = self.builder.ssa.header_block(ebb);
// Then we change the cursor position. // Then we change the cursor position.
self.position = Position { ebb, basic_block }; self.position = Position { ebb, basic_block };
self.ebb_args_adjustment(ebb, jump_args); self.ebb_params_adjustment(ebb, jump_args);
self.func.dfg.ebb_args(ebb) self.func.dfg.ebb_params(ebb)
} }
/// Declares that all the predecessors of this block are known. /// Declares that all the predecessors of this block are known.
@@ -411,10 +411,10 @@ impl<'a, Variable> FunctionBuilder<'a, Variable>
where where
Variable: EntityRef + Default, Variable: EntityRef + Default,
{ {
/// Retrieves all the arguments for an `Ebb` currently inferred from the jump instructions /// Retrieves all the parameters for an `Ebb` currently inferred from the jump instructions
/// inserted that target it and the SSA construction. /// inserted that target it and the SSA construction.
pub fn ebb_args(&self, ebb: Ebb) -> &[Value] { pub fn ebb_params(&self, ebb: Ebb) -> &[Value] {
self.func.dfg.ebb_args(ebb) self.func.dfg.ebb_params(ebb)
} }
/// Retrieves the signature with reference `sigref` previously added with `import_signature`. /// Retrieves the signature with reference `sigref` previously added with `import_signature`.
@@ -422,14 +422,14 @@ where
self.func.dfg.signatures.get(sigref) self.func.dfg.signatures.get(sigref)
} }
/// Creates an argument for a specific `Ebb` by appending it to the list of already existing /// Creates a parameter for a specific `Ebb` by appending it to the list of already existing
/// arguments. /// parameters.
/// ///
/// **Note:** this function has to be called at the creation of the `Ebb` before adding /// **Note:** this function has to be called at the creation of the `Ebb` before adding
/// instructions to it, otherwise this could interfere with SSA construction. /// instructions to it, otherwise this could interfere with SSA construction.
pub fn append_ebb_arg(&mut self, ebb: Ebb, ty: Type) -> Value { pub fn append_ebb_param(&mut self, ebb: Ebb, ty: Type) -> Value {
debug_assert!(self.builder.ebbs[ebb].pristine); debug_assert!(self.builder.ebbs[ebb].pristine);
self.func.dfg.append_ebb_arg(ebb, ty) self.func.dfg.append_ebb_param(ebb, ty)
} }
/// Returns the result values of an instruction. /// Returns the result values of an instruction.
@@ -547,14 +547,14 @@ where
debug_assert!(self.pristine); debug_assert!(self.pristine);
for argtyp in &self.func.signature.argument_types { for argtyp in &self.func.signature.argument_types {
self.builder.function_args_values.push( self.builder.function_args_values.push(
self.func.dfg.append_ebb_arg(ebb, argtyp.value_type), self.func.dfg.append_ebb_param(ebb, argtyp.value_type),
); );
} }
self.pristine = false; self.pristine = false;
} }
fn ebb_args_adjustment(&mut self, dest_ebb: Ebb, jump_args: &[Value]) { fn ebb_params_adjustment(&mut self, dest_ebb: Ebb, jump_args: &[Value]) {
if self.builder.ssa.predecessors(dest_ebb).is_empty() || if self.builder.ssa.predecessors(dest_ebb).is_empty() ||
self.builder.ebbs[dest_ebb].pristine self.builder.ebbs[dest_ebb].pristine
{ {
@@ -562,12 +562,12 @@ where
// so the jump arguments supplied here are this Ebb' arguments // so the jump arguments supplied here are this Ebb' arguments
// However some of the arguments might already be there // However some of the arguments might already be there
// in the Ebb so we have to check they're consistent // in the Ebb so we have to check they're consistent
let dest_ebb_args_len = { let dest_ebb_params_len = {
let dest_ebb_args = self.func.dfg.ebb_args(dest_ebb); let dest_ebb_params = self.func.dfg.ebb_params(dest_ebb);
debug_assert!( debug_assert!(
dest_ebb_args dest_ebb_params
.iter() .iter()
.zip(jump_args.iter().take(dest_ebb_args.len())) .zip(jump_args.iter().take(dest_ebb_params.len()))
.all(|(dest_arg, jump_arg)| { .all(|(dest_arg, jump_arg)| {
self.func.dfg.value_type(*jump_arg) == self.func.dfg.value_type(*jump_arg) ==
self.func.dfg.value_type(*dest_arg) self.func.dfg.value_type(*dest_arg)
@@ -575,12 +575,12 @@ where
"the jump argument supplied has not the \ "the jump argument supplied has not the \
same type as the corresponding dest ebb argument" same type as the corresponding dest ebb argument"
); );
dest_ebb_args.len() dest_ebb_params.len()
}; };
self.builder.ebbs[dest_ebb].user_arg_count = jump_args.len(); self.builder.ebbs[dest_ebb].user_arg_count = jump_args.len();
for val in jump_args.iter().skip(dest_ebb_args_len) { for val in jump_args.iter().skip(dest_ebb_params_len) {
let ty = self.func.dfg.value_type(*val); let ty = self.func.dfg.value_type(*val);
self.func.dfg.append_ebb_arg(dest_ebb, ty); self.func.dfg.append_ebb_param(dest_ebb, ty);
} }
} else { } else {
// The Ebb already has predecessors // The Ebb already has predecessors
@@ -595,7 +595,7 @@ where
debug_assert!( debug_assert!(
jump_args jump_args
.iter() .iter()
.zip(self.func.dfg.ebb_args(dest_ebb).iter().take( .zip(self.func.dfg.ebb_params(dest_ebb).iter().take(
self.builder.ebbs[dest_ebb].user_arg_count, self.builder.ebbs[dest_ebb].user_arg_count,
)) ))
.all(|(jump_arg, dest_arg)| { .all(|(jump_arg, dest_arg)| {

View File

@@ -210,7 +210,7 @@ enum Call {
/// call `seal_ebb_header_block` on it with the `Function` that you are building. /// call `seal_ebb_header_block` on it with the `Function` that you are building.
/// ///
/// This API will give you the correct SSA values to use as arguments of your instructions, /// This API will give you the correct SSA values to use as arguments of your instructions,
/// as well as modify the jump instruction and `Ebb` headers arguments to account for the SSA /// as well as modify the jump instruction and `Ebb` headers parameters to account for the SSA
/// Phi functions. /// Phi functions.
/// ///
impl<Variable> SSABuilder<Variable> impl<Variable> SSABuilder<Variable>
@@ -261,18 +261,18 @@ where
fn use_var_nonlocal(&mut self, func: &mut Function, var: Variable, ty: Type, block: Block) { fn use_var_nonlocal(&mut self, func: &mut Function, var: Variable, ty: Type, block: Block) {
let case = match self.blocks[block] { let case = match self.blocks[block] {
BlockData::EbbHeader(ref mut data) => { BlockData::EbbHeader(ref mut data) => {
// The block has multiple predecessors so we append an Ebb argument that // The block has multiple predecessors so we append an Ebb parameter that
// will serve as a value. // will serve as a value.
if data.sealed { if data.sealed {
if data.predecessors.len() == 1 { if data.predecessors.len() == 1 {
// 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 = func.dfg.append_ebb_arg(data.ebb, ty); let val = func.dfg.append_ebb_param(data.ebb, ty);
UseVarCases::SealedMultiplePredecessors(val, data.ebb) UseVarCases::SealedMultiplePredecessors(val, data.ebb)
} }
} else { } else {
let val = func.dfg.append_ebb_arg(data.ebb, ty); let val = func.dfg.append_ebb_param(data.ebb, ty);
data.undef_variables.push((var, val)); data.undef_variables.push((var, val));
UseVarCases::Unsealed(val) UseVarCases::Unsealed(val)
} }
@@ -285,7 +285,7 @@ where
self.calls.push(Call::FinishSealedOnePredecessor(block)); self.calls.push(Call::FinishSealedOnePredecessor(block));
self.calls.push(Call::UseVar(pred)); self.calls.push(Call::UseVar(pred));
} }
// The block has multiple predecessors, we register the ebb argument as the current // The block has multiple predecessors, we register the EBB parameter as the current
// definition for the variable. // definition for the variable.
UseVarCases::Unsealed(val) => { UseVarCases::Unsealed(val) => {
self.def_var(var, val, block); self.def_var(var, val, block);
@@ -293,7 +293,7 @@ where
} }
UseVarCases::SealedMultiplePredecessors(val, ebb) => { UseVarCases::SealedMultiplePredecessors(val, ebb) => {
// 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 parameter
self.def_var(var, val, block); self.def_var(var, val, block);
self.begin_predecessors_lookup(val, ebb); self.begin_predecessors_lookup(val, ebb);
} }
@@ -385,7 +385,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 parameter
// only if necessary. // only if necessary.
for (var, val) in undef_vars { for (var, val) in undef_vars {
let ty = func.dfg.value_type(val); let ty = func.dfg.value_type(val);
@@ -443,7 +443,7 @@ where
} }
/// Examine the values from the predecessors and compute a result value, creating /// Examine the values from the predecessors and compute a result value, creating
/// block arguments as needed. /// block parameters as needed.
fn finish_predecessors_lookup( fn finish_predecessors_lookup(
&mut self, &mut self,
func: &mut Function, func: &mut Function,
@@ -499,7 +499,7 @@ 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.
func.dfg.remove_ebb_arg(temp_arg_val); func.dfg.remove_ebb_param(temp_arg_val);
func.dfg.change_to_alias(temp_arg_val, pred_val); func.dfg.change_to_alias(temp_arg_val, pred_val);
pred_val pred_val
} }
@@ -908,8 +908,8 @@ mod tests {
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); ssa.seal_ebb_header_block(ebb1, &mut func);
assert_eq!(func.dfg.ebb_args(ebb1)[0], z2); assert_eq!(func.dfg.ebb_params(ebb1)[0], z2);
assert_eq!(func.dfg.ebb_args(ebb1)[1], y3); assert_eq!(func.dfg.ebb_params(ebb1)[1], y3);
assert_eq!(func.dfg.resolve_aliases(x3), x1); assert_eq!(func.dfg.resolve_aliases(x3), x1);
} }
@@ -1027,9 +1027,9 @@ mod tests {
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(&mut func, z_var, I32, block1).0; let z2 = ssa.use_var(&mut func, z_var, I32, block1).0;
assert_eq!(func.dfg.ebb_args(ebb1)[0], z2); assert_eq!(func.dfg.ebb_params(ebb1)[0], z2);
let x2 = ssa.use_var(&mut func, x_var, I32, block1).0; let x2 = ssa.use_var(&mut func, x_var, I32, block1).0;
assert_eq!(func.dfg.ebb_args(ebb1)[1], x2); assert_eq!(func.dfg.ebb_params(ebb1)[1], x2);
let x3 = { let x3 = {
let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
cur.ins().iadd(x2, z2) cur.ins().iadd(x2, z2)
@@ -1037,7 +1037,7 @@ mod tests {
ssa.def_var(x_var, x3, block1); ssa.def_var(x_var, x3, block1);
let x4 = ssa.use_var(&mut func, x_var, I32, block1).0; let x4 = ssa.use_var(&mut func, x_var, I32, block1).0;
let y3 = ssa.use_var(&mut func, y_var, I32, block1).0; let y3 = ssa.use_var(&mut func, y_var, I32, block1).0;
assert_eq!(func.dfg.ebb_args(ebb1)[2], y3); assert_eq!(func.dfg.ebb_params(ebb1)[2], y3);
let y4 = { let y4 = {
let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1); let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
cur.ins().isub(y3, x4) cur.ins().isub(y3, x4)
@@ -1051,7 +1051,7 @@ mod tests {
ssa.seal_ebb_header_block(ebb1, &mut func); 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_params(ebb1)[1], y3);
assert_eq!(func.dfg.ebb_args(ebb1)[0], x2); assert_eq!(func.dfg.ebb_params(ebb1)[0], x2);
} }
} }

View File

@@ -1362,7 +1362,7 @@ impl<'a> Parser<'a> {
// Parse an extended basic block, add contents to `ctx`. // Parse an extended basic block, add contents to `ctx`.
// //
// extended-basic-block ::= * ebb-header { instruction } // extended-basic-block ::= * ebb-header { instruction }
// ebb-header ::= Ebb(ebb) [ebb-args] ":" // ebb-header ::= Ebb(ebb) [ebb-params] ":"
// //
fn parse_extended_basic_block(&mut self, ctx: &mut Context) -> Result<()> { fn parse_extended_basic_block(&mut self, ctx: &mut Context) -> Result<()> {
let ebb_num = self.match_ebb("expected EBB header")?; let ebb_num = self.match_ebb("expected EBB header")?;
@@ -1370,8 +1370,8 @@ impl<'a> Parser<'a> {
self.gather_comments(ebb); self.gather_comments(ebb);
if !self.optional(Token::Colon) { if !self.optional(Token::Colon) {
// ebb-header ::= Ebb(ebb) [ * ebb-args ] ":" // ebb-header ::= Ebb(ebb) [ * ebb-params ] ":"
self.parse_ebb_args(ctx, ebb)?; self.parse_ebb_params(ctx, ebb)?;
self.match_token( self.match_token(
Token::Colon, Token::Colon,
"expected ':' after EBB arguments", "expected ':' after EBB arguments",
@@ -1429,27 +1429,27 @@ impl<'a> Parser<'a> {
Ok(()) Ok(())
} }
// Parse parenthesized list of EBB arguments. Returns a vector of (u32, Type) pairs with the // Parse parenthesized list of EBB parameters. Returns a vector of (u32, Type) pairs with the
// source value numbers of the defined values and the defined types. // source value numbers of the defined values and the defined types.
// //
// ebb-args ::= * "(" ebb-arg { "," ebb-arg } ")" // ebb-params ::= * "(" ebb-param { "," ebb-param } ")"
fn parse_ebb_args(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> { fn parse_ebb_params(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> {
// ebb-args ::= * "(" ebb-arg { "," ebb-arg } ")" // ebb-params ::= * "(" ebb-param { "," ebb-param } ")"
self.match_token( self.match_token(
Token::LPar, Token::LPar,
"expected '(' before EBB arguments", "expected '(' before EBB arguments",
)?; )?;
// ebb-args ::= "(" * ebb-arg { "," ebb-arg } ")" // ebb-params ::= "(" * ebb-param { "," ebb-param } ")"
self.parse_ebb_arg(ctx, ebb)?; self.parse_ebb_param(ctx, ebb)?;
// ebb-args ::= "(" ebb-arg * { "," ebb-arg } ")" // ebb-params ::= "(" ebb-param * { "," ebb-param } ")"
while self.optional(Token::Comma) { while self.optional(Token::Comma) {
// ebb-args ::= "(" ebb-arg { "," * ebb-arg } ")" // ebb-params ::= "(" ebb-param { "," * ebb-param } ")"
self.parse_ebb_arg(ctx, ebb)?; self.parse_ebb_param(ctx, ebb)?;
} }
// ebb-args ::= "(" ebb-arg { "," ebb-arg } * ")" // ebb-params ::= "(" ebb-param { "," ebb-param } * ")"
self.match_token( self.match_token(
Token::RPar, Token::RPar,
"expected ')' after EBB arguments", "expected ')' after EBB arguments",
@@ -1458,27 +1458,27 @@ impl<'a> Parser<'a> {
Ok(()) Ok(())
} }
// Parse a single EBB argument declaration, and append it to `ebb`. // Parse a single EBB parameter declaration, and append it to `ebb`.
// //
// ebb-arg ::= * Value(v) ":" Type(t) arg-loc? // ebb-param ::= * Value(v) ":" Type(t) arg-loc?
// arg-loc ::= "[" value-location "]" // arg-loc ::= "[" value-location "]"
// //
fn parse_ebb_arg(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> { fn parse_ebb_param(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> {
// ebb-arg ::= * Value(v) ":" Type(t) arg-loc? // ebb-param ::= * Value(v) ":" Type(t) arg-loc?
let v = self.match_value("EBB argument must be a value")?; let v = self.match_value("EBB argument must be a value")?;
let v_location = self.loc; let v_location = self.loc;
// ebb-arg ::= Value(v) * ":" Type(t) arg-loc? // ebb-param ::= Value(v) * ":" Type(t) arg-loc?
self.match_token( self.match_token(
Token::Colon, Token::Colon,
"expected ':' after EBB argument", "expected ':' after EBB argument",
)?; )?;
// ebb-arg ::= Value(v) ":" * Type(t) arg-loc? // ebb-param ::= Value(v) ":" * Type(t) arg-loc?
let t = self.match_type("expected EBB argument type")?; let t = self.match_type("expected EBB argument type")?;
// Allocate the EBB argument and add the mapping. // Allocate the EBB argument and add the mapping.
let value = ctx.function.dfg.append_ebb_arg(ebb, t); let value = ctx.function.dfg.append_ebb_param(ebb, t);
ctx.map.def_value(v, value, &v_location)?; ctx.map.def_value(v, value, &v_location)?;
// ebb-arg ::= Value(v) ":" Type(t) * arg-loc? // ebb-param ::= Value(v) ":" Type(t) * arg-loc?
if self.optional(Token::LBracket) { if self.optional(Token::LBracket) {
let loc = self.parse_value_location(ctx)?; let loc = self.parse_value_location(ctx)?;
ctx.function.locations[value] = loc; ctx.function.locations[value] = loc;
@@ -2473,10 +2473,10 @@ mod tests {
let mut ebbs = func.layout.ebbs(); let mut ebbs = func.layout.ebbs();
let ebb0 = ebbs.next().unwrap(); let ebb0 = ebbs.next().unwrap();
assert_eq!(func.dfg.ebb_args(ebb0), &[]); assert_eq!(func.dfg.ebb_params(ebb0), &[]);
let ebb4 = ebbs.next().unwrap(); let ebb4 = ebbs.next().unwrap();
let ebb4_args = func.dfg.ebb_args(ebb4); let ebb4_args = func.dfg.ebb_params(ebb4);
assert_eq!(ebb4_args.len(), 1); assert_eq!(ebb4_args.len(), 1);
assert_eq!(func.dfg.value_type(ebb4_args[0]), types::I32); assert_eq!(func.dfg.value_type(ebb4_args[0]), types::I32);
} }

View File

@@ -121,7 +121,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
Operator::Block { ty } => { Operator::Block { ty } => {
let next = builder.create_ebb(); let next = builder.create_ebb();
if let Ok(ty_cre) = type_to_type(&ty) { if let Ok(ty_cre) = type_to_type(&ty) {
builder.append_ebb_arg(next, ty_cre); builder.append_ebb_param(next, ty_cre);
} }
state.push_block(next, num_return_values(ty)); state.push_block(next, num_return_values(ty));
} }
@@ -129,7 +129,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let loop_body = builder.create_ebb(); let loop_body = builder.create_ebb();
let next = builder.create_ebb(); let next = builder.create_ebb();
if let Ok(ty_cre) = type_to_type(&ty) { if let Ok(ty_cre) = type_to_type(&ty) {
builder.append_ebb_arg(next, ty_cre); builder.append_ebb_param(next, ty_cre);
} }
builder.ins().jump(loop_body, &[]); builder.ins().jump(loop_body, &[]);
state.push_loop(loop_body, next, num_return_values(ty)); state.push_loop(loop_body, next, num_return_values(ty));
@@ -146,7 +146,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
// - either the If have an Else clause, in that case the destination of this jump // - either the If have an Else clause, in that case the destination of this jump
// instruction will be changed later when we translate the Else operator. // instruction will be changed later when we translate the Else operator.
if let Ok(ty_cre) = type_to_type(&ty) { if let Ok(ty_cre) = type_to_type(&ty) {
builder.append_ebb_arg(if_not, ty_cre); builder.append_ebb_param(if_not, ty_cre);
} }
state.push_if(jump_inst, if_not, num_return_values(ty)); state.push_if(jump_inst, if_not, num_return_values(ty));
} }
@@ -190,7 +190,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
} }
state.stack.truncate(frame.original_stack_size()); state.stack.truncate(frame.original_stack_size());
state.stack.extend_from_slice( state.stack.extend_from_slice(
builder.ebb_args(frame.following_code()), builder.ebb_params(frame.following_code()),
); );
} }
/**************************** Branch instructions ********************************* /**************************** Branch instructions *********************************
@@ -876,7 +876,7 @@ fn translate_unreachable_operator(
// And add the return values of the block but only if the next block is reachble // And add the return values of the block but only if the next block is reachble
// (which corresponds to testing if the stack depth is 1) // (which corresponds to testing if the stack depth is 1)
if state.real_unreachable_stack_depth == 1 { if state.real_unreachable_stack_depth == 1 {
stack.extend_from_slice(builder.ebb_args(frame.following_code())); stack.extend_from_slice(builder.ebb_params(frame.following_code()));
} }
state.real_unreachable_stack_depth -= 1; state.real_unreachable_stack_depth -= 1;
} }