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-
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
that can be referenced inside the function. In the example above, the preamble
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
dominated by the definition.
Cretonne does not have phi instructions but uses *EBB arguments* instead. An EBB
can be defined with a list of typed arguments. Whenever control is transferred
to the EBB, values for the arguments must be provided. When entering a function,
the incoming function arguments are passed as arguments to the entry EBB.
Cretonne does not have phi instructions but uses :term:`EBB parameter`\s
instead. An EBB can be defined with a list of typed parameters. Whenever control
is transferred to the EBB, argument values for the parameters must be provided.
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
EBB arguments or instruction results.
EBB parameters or instruction results.
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
``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 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
instructions are encoded as follows:
- 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
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
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:: 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
-----------------------------
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.
.. 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
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
target function may be determined dynamically at runtime, but the signature
must be known when the function call is compiled. The function signature
describes how to call the function, including arguments, return values, and the
calling convention:
target function may be determined dynamically at runtime, but the signature must
be known when the function call is compiled. The function signature describes
how to call the function, including parameters, return values, and the calling
convention:
.. productionlist::
signature : "(" [arglist] ")" ["->" retlist] [call_conv]
arglist : arg { "," arg }
retlist : arglist
arg : type [argext] [argspecial]
argext : "uext" | "sext"
argspecial: "sret" | "link" | "fp" | "csr" | "vmctx"
callconv : `string`
signature : "(" [paramlist] ")" ["->" retlist] [call_conv]
paramlist : param { "," param }
retlist : paramlist
param : type [paramext] [paramspecial]
paramext : "uext" | "sext"
paramspecial : "sret" | "link" | "fp" | "csr" | "vmctx"
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
platform. When calling other Cretonne functions, the flags are not necessary.
@@ -411,19 +418,11 @@ preamble`:
.. autoinst:: call
.. 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" {
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)
br ebb1(v2, v4)
ebb2:
return v1
}
.. literalinclude:: callex.cton
:language: cton
:lines: 3-
Indirect function calls use a signature declared in the preamble.
@@ -682,15 +681,15 @@ bounds checking is required for each access:
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
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:: f32const
.. 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.udivmodx
.. autoinst:: isa.intel.instructions.cvtt2si
.. autoinst:: isa.intel.instructions.fmin
.. autoinst:: isa.intel.instructions.fmax
Instruction groups
==================
@@ -1034,6 +1036,18 @@ Glossary
control flow graph where only the root can be a join node. This
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
A function signature describes how to call a function. It consists of:

View File

@@ -1,12 +1,12 @@
test verifier
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
}
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
}

View File

@@ -450,7 +450,7 @@ mod test {
fn unreachable_node() {
let mut func = Function::new();
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 ebb2 = func.dfg.make_ebb();
@@ -479,7 +479,7 @@ mod test {
fn non_zero_entry_block() {
let mut func = Function::new();
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 ebb2 = func.dfg.make_ebb();
let ebb0 = func.dfg.make_ebb();

View File

@@ -185,7 +185,7 @@ mod tests {
fn branches_and_jumps() {
let mut func = Function::new();
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 ebb2 = func.dfg.make_ebb();

View File

@@ -223,7 +223,7 @@ mod tests {
fn types() {
let mut func = Function::new();
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);
pos.insert_ebb(ebb0);
@@ -244,14 +244,14 @@ mod tests {
fn reuse_results() {
let mut func = Function::new();
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);
pos.insert_ebb(ebb0);
let v0 = pos.ins().iadd_imm(arg0, 17);
assert_eq!(pos.func.dfg.value_type(v0), I32);
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.
pos.func.dfg.clear_results(iadd);
@@ -260,6 +260,6 @@ mod tests {
assert_eq!(pos.current_inst(), Some(iadd));
let iconst = pos.prev_inst().unwrap();
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
/// 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
/// `FunctionLayout` data structure which form the other half of the function representation.
@@ -34,7 +34,8 @@ pub struct DataFlowGraph {
/// primary `insts` map.
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
/// instructions contained in each EBB.
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.
/// - Instruction result values in `results`.
/// - EBB arguments in `ebbs`.
/// - EBB parameters in `ebbs`.
pub value_lists: ValueListPool,
/// Primary value table with entries for all values.
@@ -135,7 +136,7 @@ fn resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Value
/// Handling values.
///
/// Values are either EBB arguments or instruction results.
/// Values are either EBB parameters or instruction results.
impl DataFlowGraph {
/// Allocate an extended value entry.
fn make_value(&mut self, data: ValueData) -> Value {
@@ -151,7 +152,7 @@ impl DataFlowGraph {
pub fn value_type(&self, v: Value) -> Type {
match self.values[v] {
ValueData::Inst { ty, .. } |
ValueData::Arg { ty, .. } |
ValueData::Param { ty, .. } |
ValueData::Alias { ty, .. } => ty,
}
}
@@ -159,7 +160,7 @@ impl DataFlowGraph {
/// Get the definition of a value.
///
/// 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 {
match self.values[v] {
ValueData::Inst { inst, num, .. } => {
@@ -170,15 +171,15 @@ impl DataFlowGraph {
v,
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!(
Some(v),
self.ebbs[ebb].args.get(num as usize, &self.value_lists),
"Dangling EBB argument value"
self.ebbs[ebb].params.get(num as usize, &self.value_lists),
"Dangling EBB parameter value"
);
ValueDef::Arg(ebb, num as usize)
ValueDef::Param(ebb, num as usize)
}
ValueData::Alias { original, .. } => {
// 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.
///
@@ -198,7 +199,7 @@ impl DataFlowGraph {
use self::ValueData::*;
match self.values[v] {
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,
}
}
@@ -317,16 +318,16 @@ impl DataFlowGraph {
#[derive(Debug, PartialEq, Eq)]
pub enum ValueDef {
/// Value is the n'th result of an instruction.
Res(Inst, usize),
/// Value is the n'th argument to an EBB.
Arg(Ebb, usize),
Result(Inst, usize),
/// Value is the n'th parameter to an EBB.
Param(Ebb, usize),
}
impl ValueDef {
/// Unwrap the instruction where the value was defined, or panic.
pub fn unwrap_inst(&self) -> Inst {
match *self {
ValueDef::Res(inst, _) => inst,
ValueDef::Result(inst, _) => inst,
_ => panic!("Value is not an instruction result"),
}
}
@@ -338,11 +339,11 @@ enum ValueData {
// Value is defined by an instruction.
Inst { ty: Type, num: u16, inst: Inst },
// Value is an EBB argument.
Arg { ty: Type, num: u16, ebb: Ebb },
// Value is an EBB parameter.
Param { ty: Type, num: u16, ebb: Ebb },
// 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.
Alias { ty: Type, original: Value },
}
@@ -678,83 +679,82 @@ impl DataFlowGraph {
self.ebbs.push(EbbData::new())
}
/// Get the number of arguments on `ebb`.
pub fn num_ebb_args(&self, ebb: Ebb) -> usize {
self.ebbs[ebb].args.len(&self.value_lists)
/// Get the number of parameters on `ebb`.
pub fn num_ebb_params(&self, ebb: Ebb) -> usize {
self.ebbs[ebb].params.len(&self.value_lists)
}
/// Get the arguments to an EBB.
pub fn ebb_args(&self, ebb: Ebb) -> &[Value] {
self.ebbs[ebb].args.as_slice(&self.value_lists)
/// Get the parameters on `ebb`.
pub fn ebb_params(&self, ebb: Ebb) -> &[Value] {
self.ebbs[ebb].params.as_slice(&self.value_lists)
}
/// Append an argument with type `ty` to `ebb`.
pub fn append_ebb_arg(&mut self, ebb: Ebb, ty: Type) -> Value {
let arg = self.values.next_key();
let num = self.ebbs[ebb].args.push(arg, &mut self.value_lists);
assert!(num <= u16::MAX as usize, "Too many arguments to EBB");
self.make_value(ValueData::Arg {
/// Append a parameter with type `ty` to `ebb`.
pub fn append_ebb_param(&mut self, ebb: Ebb, ty: Type) -> Value {
let param = self.values.next_key();
let num = self.ebbs[ebb].params.push(param, &mut self.value_lists);
assert!(num <= u16::MAX as usize, "Too many parameters on EBB");
self.make_value(ValueData::Param {
ty,
num: num as u16,
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.
///
/// *Important*: to ensure O(1) deletion, this method swaps the removed argument with the
/// last `Ebb` argument. This can disrupt all the branch instructions jumping to this
/// `Ebb` for which you have to change the jump argument order if necessary.
/// *Important*: to ensure O(1) deletion, this method swaps the removed parameter with the
/// last `ebb`` parameter. This can disrupt all the branch instructions jumping to this
/// `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
/// swapped.
pub fn swap_remove_ebb_arg(&mut self, val: Value) -> usize {
let (ebb, num) = if let ValueData::Arg { num, ebb, .. } = self.values[val] {
/// Panics if `val` is not an EBB parameter.
pub fn swap_remove_ebb_param(&mut self, val: Value) -> usize {
let (ebb, num) = if let ValueData::Param { num, ebb, .. } = self.values[val] {
(ebb, num)
} 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,
&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.
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;
} 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
}
/// Removes `val` from `ebb`'s arguments by a standard linear time list removal which preserves
/// ordering. Also updates the values' data.
pub fn remove_ebb_arg(&mut self, val: Value) {
let (ebb, num) = if let ValueData::Arg { num, ebb, .. } = self.values[val] {
/// Removes `val` from `ebb`'s parameters by a standard linear time list removal which
/// preserves ordering. Also updates the values' data.
pub fn remove_ebb_param(&mut self, val: Value) {
let (ebb, num) = if let ValueData::Param { num, ebb, .. } = self.values[val] {
(ebb, num)
} 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,
&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]
.args
.params
.get(index as usize, &self.value_lists)
.unwrap()] {
ValueData::Arg { ref mut num, .. } => {
ValueData::Param { ref mut num, .. } => {
*num -= 1;
}
_ => {
panic!(
"{} must be an EBB argument",
"{} must be an EBB parameter",
self.ebbs[ebb]
.args
.params
.get(index as usize, &self.value_lists)
.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.
///
/// In almost all cases, you should be using `append_ebb_arg()` instead of this method.
pub fn attach_ebb_arg(&mut self, ebb: Ebb, arg: Value) {
assert!(!self.value_is_attached(arg));
let num = self.ebbs[ebb].args.push(arg, &mut self.value_lists);
assert!(num <= u16::MAX as usize, "Too many arguments to EBB");
let ty = self.value_type(arg);
self.values[arg] = ValueData::Arg {
/// In almost all cases, you should be using `append_ebb_param()` instead of this method.
pub fn attach_ebb_param(&mut self, ebb: Ebb, param: Value) {
assert!(!self.value_is_attached(param));
let num = self.ebbs[ebb].params.push(param, &mut self.value_lists);
assert!(num <= u16::MAX as usize, "Too many parameters on EBB");
let ty = self.value_type(param);
self.values[param] = ValueData::Param {
ty,
num: num as u16,
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
/// of arguments 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.
/// The `old_value` must be an attached EBB parameter. It is removed from its place in the list
/// of parameters and replaced by a new value of type `new_type`. The new value gets the same
/// 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.
///
/// 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.
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)
} 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,
num,
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
}
/// 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
/// is to put them back on the same EBB with `attach_ebb_arg()` or change them into aliases
/// 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_param()` or change them into aliases
/// with `change_to_alias()`.
pub fn detach_ebb_args(&mut self, ebb: Ebb) -> ValueList {
self.ebbs[ebb].args.take()
pub fn detach_ebb_params(&mut self, ebb: Ebb) -> ValueList {
self.ebbs[ebb].params.take()
}
}
// 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
// match the function arguments.
#[derive(Clone)]
struct EbbData {
// List of arguments to this EBB.
args: ValueList,
// List of parameters to this EBB.
params: ValueList,
}
impl EbbData {
fn new() -> EbbData {
EbbData { args: ValueList::new() }
EbbData { params: ValueList::new() }
}
}
@@ -899,7 +899,7 @@ mod tests {
let val = dfg.first_result(inst);
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);
// Replacing results.
@@ -908,7 +908,7 @@ mod tests {
assert!(!dfg.value_is_attached(val));
assert!(dfg.value_is_attached(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);
}
@@ -933,90 +933,90 @@ mod tests {
let ebb = dfg.make_ebb();
assert_eq!(ebb.to_string(), "ebb0");
assert_eq!(dfg.num_ebb_args(ebb), 0);
assert_eq!(dfg.ebb_args(ebb), &[]);
assert!(dfg.detach_ebb_args(ebb).is_empty());
assert_eq!(dfg.num_ebb_args(ebb), 0);
assert_eq!(dfg.ebb_args(ebb), &[]);
assert_eq!(dfg.num_ebb_params(ebb), 0);
assert_eq!(dfg.ebb_params(ebb), &[]);
assert!(dfg.detach_ebb_params(ebb).is_empty());
assert_eq!(dfg.num_ebb_params(ebb), 0);
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!(dfg.num_ebb_args(ebb), 1);
assert_eq!(dfg.ebb_args(ebb), &[arg1]);
assert_eq!(dfg.num_ebb_params(ebb), 1);
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!(dfg.num_ebb_args(ebb), 2);
assert_eq!(dfg.ebb_args(ebb), &[arg1, arg2]);
assert_eq!(dfg.num_ebb_params(ebb), 2);
assert_eq!(dfg.ebb_params(ebb), &[arg1, arg2]);
assert_eq!(dfg.value_def(arg1), ValueDef::Arg(ebb, 0));
assert_eq!(dfg.value_def(arg2), ValueDef::Arg(ebb, 1));
assert_eq!(dfg.value_def(arg1), ValueDef::Param(ebb, 0));
assert_eq!(dfg.value_def(arg2), ValueDef::Param(ebb, 1));
assert_eq!(dfg.value_type(arg1), types::F32);
assert_eq!(dfg.value_type(arg2), types::I16);
// Swap the two EBB arguments.
let vlist = dfg.detach_ebb_args(ebb);
assert_eq!(dfg.num_ebb_args(ebb), 0);
assert_eq!(dfg.ebb_args(ebb), &[]);
// Swap the two EBB parameters.
let vlist = dfg.detach_ebb_params(ebb);
assert_eq!(dfg.num_ebb_params(ebb), 0);
assert_eq!(dfg.ebb_params(ebb), &[]);
assert_eq!(vlist.as_slice(&dfg.value_lists), &[arg1, arg2]);
dfg.attach_ebb_arg(ebb, arg2);
let arg3 = dfg.append_ebb_arg(ebb, types::I32);
dfg.attach_ebb_arg(ebb, arg1);
assert_eq!(dfg.ebb_args(ebb), &[arg2, arg3, arg1]);
dfg.attach_ebb_param(ebb, arg2);
let arg3 = dfg.append_ebb_param(ebb, types::I32);
dfg.attach_ebb_param(ebb, arg1);
assert_eq!(dfg.ebb_params(ebb), &[arg2, arg3, arg1]);
}
#[test]
fn replace_ebb_arguments() {
fn replace_ebb_params() {
let mut dfg = DataFlowGraph::new();
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(new1), types::I64);
assert_eq!(dfg.ebb_args(ebb), &[new1]);
assert_eq!(dfg.ebb_params(ebb), &[new1]);
dfg.attach_ebb_arg(ebb, arg1);
assert_eq!(dfg.ebb_args(ebb), &[new1, arg1]);
dfg.attach_ebb_param(ebb, 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(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);
assert_eq!(dfg.ebb_args(ebb), &[new1, new2, arg1]);
dfg.attach_ebb_param(ebb, 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(new2), types::I8);
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]
fn swap_remove_ebb_arguments() {
fn swap_remove_ebb_params() {
let mut dfg = DataFlowGraph::new();
let ebb = dfg.make_ebb();
let arg1 = dfg.append_ebb_arg(ebb, types::F32);
let arg2 = dfg.append_ebb_arg(ebb, types::F32);
let arg3 = dfg.append_ebb_arg(ebb, types::F32);
assert_eq!(dfg.ebb_args(ebb), &[arg1, arg2, arg3]);
let arg1 = dfg.append_ebb_param(ebb, types::F32);
let arg2 = dfg.append_ebb_param(ebb, types::F32);
let arg3 = dfg.append_ebb_param(ebb, types::F32);
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(arg2), true);
assert_eq!(dfg.value_is_attached(arg3), true);
assert_eq!(dfg.ebb_args(ebb), &[arg3, arg2]);
dfg.swap_remove_ebb_arg(arg2);
assert_eq!(dfg.ebb_params(ebb), &[arg3, arg2]);
dfg.swap_remove_ebb_param(arg2);
assert_eq!(dfg.value_is_attached(arg2), false);
assert_eq!(dfg.value_is_attached(arg3), true);
assert_eq!(dfg.ebb_args(ebb), &[arg3]);
dfg.swap_remove_ebb_arg(arg3);
assert_eq!(dfg.ebb_params(ebb), &[arg3]);
dfg.swap_remove_ebb_param(arg3);
assert_eq!(dfg.value_is_attached(arg3), false);
assert_eq!(dfg.ebb_args(ebb), &[]);
assert_eq!(dfg.ebb_params(ebb), &[]);
}
#[test]
@@ -1035,10 +1035,10 @@ mod tests {
// Make sure we can resolve value aliases even when values is empty.
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 iadd = match pos.func.dfg.value_def(s) {
ValueDef::Res(i, 0) => i,
ValueDef::Result(i, 0) => i,
_ => panic!(),
};

View File

@@ -150,7 +150,7 @@ impl Function {
pub fn special_arg(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> {
let entry = self.layout.entry_block().expect("Function is empty");
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 {
fn from(def: ValueDef) -> ProgramPoint {
match def {
ValueDef::Res(inst, _) => inst.into(),
ValueDef::Arg(ebb, _) => ebb.into(),
ValueDef::Result(inst, _) => inst.into(),
ValueDef::Param(ebb, _) => ebb.into(),
}
}
}
@@ -66,8 +66,8 @@ impl From<Ebb> for ExpandedProgramPoint {
impl From<ValueDef> for ExpandedProgramPoint {
fn from(def: ValueDef) -> ExpandedProgramPoint {
match def {
ValueDef::Res(inst, _) => inst.into(),
ValueDef::Arg(ebb, _) => ebb.into(),
ValueDef::Result(inst, _) => inst.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 ty = func.dfg.value_type(result);
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);
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 ty = func.dfg.value_type(result);
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.
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.
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.
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.
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);
pos.use_srcloc(inst);

View File

@@ -136,8 +136,8 @@ mod tests {
let mut dfg = DataFlowGraph::new();
let ebb = dfg.make_ebb();
let arg64 = dfg.append_ebb_arg(ebb, types::I64);
let arg32 = dfg.append_ebb_arg(ebb, types::I32);
let arg64 = dfg.append_ebb_param(ebb, types::I64);
let arg32 = dfg.append_ebb_param(ebb, types::I32);
// Try to encode iadd_imm.i64 v1, -10.
let inst64 = InstructionData::BinaryImm {
@@ -180,8 +180,8 @@ mod tests {
let mut dfg = DataFlowGraph::new();
let ebb = dfg.make_ebb();
let arg64 = dfg.append_ebb_arg(ebb, types::I64);
let arg32 = dfg.append_ebb_arg(ebb, types::I32);
let arg64 = dfg.append_ebb_param(ebb, types::I64);
let arg32 = dfg.append_ebb_param(ebb, types::I32);
// Try to encode iadd_imm.i64 v1, -10.
let inst64 = InstructionData::BinaryImm {
@@ -237,7 +237,7 @@ mod tests {
let mut dfg = DataFlowGraph::new();
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.
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.
let mut abi_arg = 0;
// Process the EBB arguments one at a time, possibly replacing one argument with multiple new
// ones. We do this by detaching the entry EBB arguments first.
let ebb_args = pos.func.dfg.detach_ebb_args(entry);
// Process the EBB parameters one at a time, possibly replacing one argument with multiple new
// ones. We do this by detaching the entry EBB parameters first.
let ebb_params = pos.func.dfg.detach_ebb_params(entry);
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;
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 {
// No value translation is necessary, this argument matches the ABI type.
// 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 {
ArgumentPurpose::Normal => {}
ArgumentPurpose::StructReturn => {
@@ -108,7 +108,7 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) {
);
if ty == abi_type.value_type {
abi_arg += 1;
Ok(func.dfg.append_ebb_arg(entry, ty))
Ok(func.dfg.append_ebb_param(entry, ty))
} else {
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()`
// 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.");
// Get the corresponding entry block value and add it to the return instruction's
// arguments.
let val = pos.func.dfg.ebb_args(
let val = pos.func.dfg.ebb_params(
pos.func.layout.entry_block().unwrap(),
)
[idx];
@@ -611,7 +611,9 @@ pub fn handle_return_abi(inst: Inst, func: &mut Function, cfg: &ControlFlowGraph
/// stack slot already during legalization.
fn spill_entry_arguments(func: &mut Function, entry: Ebb) {
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 {

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.
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.
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.
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);
func.dfg.clear_results(inst);
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]);
let mut pos = FuncCursor::new(func).after_inst(inst);

View File

@@ -194,7 +194,7 @@ fn split_value(
let mut reuse = None;
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`
// instruction.
if let InstructionData::Binary { opcode, args, .. } = pos.func.dfg[inst] {
@@ -204,11 +204,11 @@ fn split_value(
}
}
}
ValueDef::Arg(ebb, num) => {
// This is an EBB argument. We can split the argument value unless this is the entry
ValueDef::Param(ebb, num) => {
// This is an EBB parameter. We can split the parameter value unless this is the entry
// block.
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.
let ty = pos.func.dfg.value_type(value);
let split_type = match concat {
@@ -217,20 +217,20 @@ fn split_value(
_ => panic!("Unhandled concat opcode: {}", concat),
};
// Since the `repairs` stack potentially contains other argument numbers for `ebb`,
// avoid shifting and renumbering EBB arguments. It could invalidate other
// Since the `repairs` stack potentially contains other parameter numbers for
// `ebb`, avoid shifting and renumbering EBB parameters. It could invalidate other
// `repairs` entries.
//
// Replace the original `value` with the low part, and append the high part at the
// end of the argument list.
let lo = pos.func.dfg.replace_ebb_arg(value, split_type);
let hi_num = pos.func.dfg.num_ebb_args(ebb);
let hi = pos.func.dfg.append_ebb_arg(ebb, split_type);
let lo = pos.func.dfg.replace_ebb_param(value, split_type);
let hi_num = pos.func.dfg.num_ebb_params(ebb);
let hi = pos.func.dfg.append_ebb_param(ebb, split_type);
reuse = Some((lo, hi));
// 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.
//
// 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,
);
// 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.
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 concat_opc;
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;
concat_opc = match dfg[inst].opcode() {
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.
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 {
return dfg.inst_args(inst)[split_res];
}

View File

@@ -63,7 +63,7 @@ fn create_pre_header(
domtree: &DominatorTree,
) -> Ebb {
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
.clone()
.into_iter()
@@ -72,7 +72,7 @@ fn create_pre_header(
let pre_header = func.dfg.make_ebb();
let mut pre_header_args_value: EntityList<Value> = EntityList::new();
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) {
// 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.
for ebb in postorder_ebbs_loop(loop_analysis, cfg, lp).iter().rev() {
// 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);
}
pos.goto_top(*ebb);

View File

@@ -236,7 +236,7 @@ mod test {
let ebb1 = func.dfg.make_ebb();
let ebb2 = 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);
@@ -288,7 +288,7 @@ mod test {
let ebb3 = func.dfg.make_ebb();
let ebb4 = 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);

View File

@@ -2,8 +2,8 @@
//!
//! 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
//! and inserting copies where necessary such that all values passed to an EBB argument will belong
//! to the same virtual register as the EBB argument value itself.
//! and inserting copies where necessary such that all argument values passed to an EBB parameter
//! will belong to the same virtual register as the EBB parameter value itself.
use cursor::{Cursor, EncCursor};
use dbg::DisplayList;
@@ -289,8 +289,8 @@ impl Coalescing {
for &ebb in domtree.cfg_postorder() {
let preds = cfg.get_predecessors(ebb);
if !preds.is_empty() {
for argnum in 0..context.func.dfg.num_ebb_args(ebb) {
context.coalesce_ebb_arg(ebb, argnum, preds)
for argnum in 0..context.func.dfg.num_ebb_params(ebb) {
context.coalesce_ebb_param(ebb, argnum, preds)
}
}
}
@@ -298,10 +298,10 @@ impl Coalescing {
}
impl<'a> Context<'a> {
/// Coalesce the `argnum`'th argument to `ebb`.
fn coalesce_ebb_arg(&mut self, ebb: Ebb, argnum: usize, preds: &[BasicBlock]) {
/// Coalesce the `argnum`'th parameter on `ebb`.
fn coalesce_ebb_param(&mut self, ebb: Ebb, argnum: usize, preds: &[BasicBlock]) {
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);
// 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
// pre-spilled, and the rest of the virtual register would be forced to spill to the
// `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() &&
self.func.signature.argument_types[def_num]
.location
@@ -530,7 +530,7 @@ impl<'a> Context<'a> {
/// Split the congruence class for the successor EBB value itself.
fn split_succ(&mut self, ebb: Ebb, succ_val: Value) -> Value {
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.
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
// register state.
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.
@@ -556,7 +556,7 @@ impl<'a> Context<'a> {
// Now handle the EBB arguments.
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());
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
@@ -565,7 +565,7 @@ impl<'a> Context<'a> {
ValueLoc::Unassigned => {
// 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
// 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
// be ignored.
@@ -595,13 +595,13 @@ impl<'a> Context<'a> {
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.
///
/// 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 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());
for (&dest_arg, &br_arg) in dest_args.iter().zip(br_args) {
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:
///
/// v1 = foo
@@ -938,7 +938,7 @@ impl<'a> Context<'a> {
for lv in tracker.live_mut().iter_mut().rev() {
// Keep going until we reach a value that is not defined by `inst`.
if match self.cur.func.dfg.value_def(lv.value) {
ValueDef::Res(i, _) => i != inst,
ValueDef::Result(i, _) => i != inst,
_ => 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();
for &value in dfg.ebb_args(ebb) {
let lr = liveness.get(value).expect(
"EBB argument value has no live range",
);
for &value in dfg.ebb_params(ebb) {
let lr = &liveness[value];
assert_eq!(lr.def(), ebb.into());
match lr.def_local_end().into() {
ExpandedProgramPoint::Inst(endpoint) => {
self.live.push(value, endpoint, lr);
}
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.
assert_eq!(
local_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.
// 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 affinity;
match func.dfg.value_def(value) {
ValueDef::Res(inst, rnum) => {
ValueDef::Result(inst, rnum) => {
def = inst.into();
// 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.
@@ -221,14 +221,14 @@ fn get_or_create<'a>(
})
.unwrap_or_default();
}
ValueDef::Arg(ebb, num) => {
ValueDef::Param(ebb, num) => {
def = ebb.into();
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.
affinity = Affinity::abi(&func.signature.argument_types[num], isa);
} 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.
affinity = Default::default();
}
@@ -290,8 +290,8 @@ pub struct Liveness {
/// It lives here to avoid repeated allocation of scratch memory.
worklist: Vec<Ebb>,
/// Working space for the `propagate_ebb_arguments` algorithm.
ebb_args: Vec<Value>,
/// Working space for the `propagate_ebb_params` algorithm.
ebb_params: Vec<Value>,
}
impl Liveness {
@@ -303,7 +303,7 @@ impl Liveness {
Liveness {
ranges: LiveRangeSet::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?
// TODO: Resolve value aliases while we're visiting instructions?
for ebb in func.layout.ebbs() {
// Make sure we have created live ranges for dead EBB arguments.
// TODO: If these arguments are really dead, we could remove them, except for the entry
// block which must match the function signature.
for &arg in func.dfg.ebb_args(ebb) {
// Make sure we have created live ranges for dead EBB parameters.
// TODO: If these parameters are really dead, we could remove them, except for the
// entry block which must match the function signature.
for &arg in func.dfg.ebb_params(ebb) {
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
/// affinity.
pub fn propagate_ebb_arguments(&mut self, func: &Function, cfg: &ControlFlowGraph) {
assert!(self.ebb_args.is_empty());
pub fn propagate_ebb_params(&mut self, func: &Function, cfg: &ControlFlowGraph) {
assert!(self.ebb_params.is_empty());
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;
if affinity.is_none() {
continue;
}
self.ebb_args.push(arg);
self.ebb_params.push(arg);
// 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) {
ValueDef::Arg(e, n) => (e, n),
ValueDef::Param(e, n) => (e, n),
_ => continue,
};
@@ -461,7 +461,7 @@ impl Liveness {
let pred_affinity = &mut self.ranges.get_mut(pred_arg).unwrap().affinity;
if pred_affinity.is_none() {
*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);
self.visit_entry_args(ebb, args);
} 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() {
// An incoming register parameter was spilled. Replace the parameter value
// 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);
self.liveness.create_dead(reg, ebb, affinity);
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);
}

View File

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

View File

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

View File

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

View File

@@ -121,7 +121,7 @@ pub fn write_ebb_header(
let regs = isa.map(TargetIsa::register_info);
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() {
None => return writeln!(w, ":"),
Some(arg) => {
@@ -177,8 +177,8 @@ fn type_suffix(func: &Function, inst: Inst) -> Option<Type> {
if constraints.use_typevar_operand() {
let ctrl_var = inst_data.typevar_operand(&func.dfg.value_lists).unwrap();
let def_ebb = match func.dfg.value_def(ctrl_var) {
ValueDef::Res(instr, _) => func.layout.inst_ebb(instr),
ValueDef::Arg(ebb, _) => Some(ebb),
ValueDef::Result(instr, _) => func.layout.inst_ebb(instr),
ValueDef::Param(ebb, _) => Some(ebb),
};
if def_ebb.is_some() && def_ebb == func.layout.inst_ebb(inst) {
return None;
@@ -465,13 +465,13 @@ mod tests {
"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!(
f.to_string(),
"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!(
f.to_string(),
"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"),
};
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);
}
None => {
@@ -273,8 +273,8 @@ where
let basic_block = self.builder.ssa.header_block(ebb);
// Then we change the cursor position.
self.position = Position { ebb, basic_block };
self.ebb_args_adjustment(ebb, jump_args);
self.func.dfg.ebb_args(ebb)
self.ebb_params_adjustment(ebb, jump_args);
self.func.dfg.ebb_params(ebb)
}
/// Declares that all the predecessors of this block are known.
@@ -411,10 +411,10 @@ impl<'a, Variable> FunctionBuilder<'a, Variable>
where
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.
pub fn ebb_args(&self, ebb: Ebb) -> &[Value] {
self.func.dfg.ebb_args(ebb)
pub fn ebb_params(&self, ebb: Ebb) -> &[Value] {
self.func.dfg.ebb_params(ebb)
}
/// Retrieves the signature with reference `sigref` previously added with `import_signature`.
@@ -422,14 +422,14 @@ where
self.func.dfg.signatures.get(sigref)
}
/// Creates an argument for a specific `Ebb` by appending it to the list of already existing
/// arguments.
/// Creates a parameter for a specific `Ebb` by appending it to the list of already existing
/// parameters.
///
/// **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.
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);
self.func.dfg.append_ebb_arg(ebb, ty)
self.func.dfg.append_ebb_param(ebb, ty)
}
/// Returns the result values of an instruction.
@@ -547,14 +547,14 @@ where
debug_assert!(self.pristine);
for argtyp in &self.func.signature.argument_types {
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;
}
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() ||
self.builder.ebbs[dest_ebb].pristine
{
@@ -562,12 +562,12 @@ where
// so the jump arguments supplied here are this Ebb' arguments
// However some of the arguments might already be there
// in the Ebb so we have to check they're consistent
let dest_ebb_args_len = {
let dest_ebb_args = self.func.dfg.ebb_args(dest_ebb);
let dest_ebb_params_len = {
let dest_ebb_params = self.func.dfg.ebb_params(dest_ebb);
debug_assert!(
dest_ebb_args
dest_ebb_params
.iter()
.zip(jump_args.iter().take(dest_ebb_args.len()))
.zip(jump_args.iter().take(dest_ebb_params.len()))
.all(|(dest_arg, jump_arg)| {
self.func.dfg.value_type(*jump_arg) ==
self.func.dfg.value_type(*dest_arg)
@@ -575,12 +575,12 @@ where
"the jump argument supplied has not the \
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();
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);
self.func.dfg.append_ebb_arg(dest_ebb, ty);
self.func.dfg.append_ebb_param(dest_ebb, ty);
}
} else {
// The Ebb already has predecessors
@@ -595,7 +595,7 @@ where
debug_assert!(
jump_args
.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,
))
.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.
///
/// 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.
///
impl<Variable> SSABuilder<Variable>
@@ -261,18 +261,18 @@ where
fn use_var_nonlocal(&mut self, func: &mut Function, var: Variable, ty: Type, block: Block) {
let case = match self.blocks[block] {
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.
if data.sealed {
if data.predecessors.len() == 1 {
// Only one predecessor, straightforward case
UseVarCases::SealedOnePredecessor(data.predecessors[0].0)
} 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)
}
} 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));
UseVarCases::Unsealed(val)
}
@@ -285,7 +285,7 @@ where
self.calls.push(Call::FinishSealedOnePredecessor(block));
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.
UseVarCases::Unsealed(val) => {
self.def_var(var, val, block);
@@ -293,7 +293,7 @@ where
}
UseVarCases::SealedMultiplePredecessors(val, ebb) => {
// 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.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.
for (var, val) in undef_vars {
let ty = func.dfg.value_type(val);
@@ -443,7 +443,7 @@ where
}
/// Examine the values from the predecessors and compute a result value, creating
/// block arguments as needed.
/// block parameters as needed.
fn finish_predecessors_lookup(
&mut self,
func: &mut Function,
@@ -499,7 +499,7 @@ where
// 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 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);
pred_val
}
@@ -908,8 +908,8 @@ mod tests {
ssa.declare_ebb_predecessor(ebb1, block3, jump_ebb2_ebb1);
ssa.seal_ebb_header_block(ebb1, &mut func);
assert_eq!(func.dfg.ebb_args(ebb1)[0], z2);
assert_eq!(func.dfg.ebb_args(ebb1)[1], y3);
assert_eq!(func.dfg.ebb_params(ebb1)[0], z2);
assert_eq!(func.dfg.ebb_params(ebb1)[1], y3);
assert_eq!(func.dfg.resolve_aliases(x3), x1);
}
@@ -1027,9 +1027,9 @@ mod tests {
let block1 = ssa.declare_ebb_header_block(ebb1);
ssa.declare_ebb_predecessor(ebb1, block0, jump_inst);
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;
assert_eq!(func.dfg.ebb_args(ebb1)[1], x2);
assert_eq!(func.dfg.ebb_params(ebb1)[1], x2);
let x3 = {
let mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
cur.ins().iadd(x2, z2)
@@ -1037,7 +1037,7 @@ mod tests {
ssa.def_var(x_var, x3, block1);
let x4 = ssa.use_var(&mut func, x_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 mut cur = FuncCursor::new(&mut func).at_bottom(ebb1);
cur.ins().isub(y3, x4)
@@ -1051,7 +1051,7 @@ mod tests {
ssa.seal_ebb_header_block(ebb1, &mut func);
// At sealing the "z" argument disappear but the remaining "x" and "y" args have to be
// in the right order.
assert_eq!(func.dfg.ebb_args(ebb1)[1], y3);
assert_eq!(func.dfg.ebb_args(ebb1)[0], x2);
assert_eq!(func.dfg.ebb_params(ebb1)[1], y3);
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`.
//
// 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<()> {
let ebb_num = self.match_ebb("expected EBB header")?;
@@ -1370,8 +1370,8 @@ impl<'a> Parser<'a> {
self.gather_comments(ebb);
if !self.optional(Token::Colon) {
// ebb-header ::= Ebb(ebb) [ * ebb-args ] ":"
self.parse_ebb_args(ctx, ebb)?;
// ebb-header ::= Ebb(ebb) [ * ebb-params ] ":"
self.parse_ebb_params(ctx, ebb)?;
self.match_token(
Token::Colon,
"expected ':' after EBB arguments",
@@ -1429,27 +1429,27 @@ impl<'a> Parser<'a> {
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.
//
// ebb-args ::= * "(" ebb-arg { "," ebb-arg } ")"
fn parse_ebb_args(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> {
// ebb-args ::= * "(" ebb-arg { "," ebb-arg } ")"
// ebb-params ::= * "(" ebb-param { "," ebb-param } ")"
fn parse_ebb_params(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> {
// ebb-params ::= * "(" ebb-param { "," ebb-param } ")"
self.match_token(
Token::LPar,
"expected '(' before EBB arguments",
)?;
// ebb-args ::= "(" * ebb-arg { "," ebb-arg } ")"
self.parse_ebb_arg(ctx, ebb)?;
// ebb-params ::= "(" * ebb-param { "," ebb-param } ")"
self.parse_ebb_param(ctx, ebb)?;
// ebb-args ::= "(" ebb-arg * { "," ebb-arg } ")"
// ebb-params ::= "(" ebb-param * { "," ebb-param } ")"
while self.optional(Token::Comma) {
// ebb-args ::= "(" ebb-arg { "," * ebb-arg } ")"
self.parse_ebb_arg(ctx, ebb)?;
// ebb-params ::= "(" ebb-param { "," * ebb-param } ")"
self.parse_ebb_param(ctx, ebb)?;
}
// ebb-args ::= "(" ebb-arg { "," ebb-arg } * ")"
// ebb-params ::= "(" ebb-param { "," ebb-param } * ")"
self.match_token(
Token::RPar,
"expected ')' after EBB arguments",
@@ -1458,27 +1458,27 @@ impl<'a> Parser<'a> {
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 "]"
//
fn parse_ebb_arg(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> {
// ebb-arg ::= * Value(v) ":" Type(t) arg-loc?
fn parse_ebb_param(&mut self, ctx: &mut Context, ebb: Ebb) -> Result<()> {
// ebb-param ::= * Value(v) ":" Type(t) arg-loc?
let v = self.match_value("EBB argument must be a value")?;
let v_location = self.loc;
// ebb-arg ::= Value(v) * ":" Type(t) arg-loc?
// ebb-param ::= Value(v) * ":" Type(t) arg-loc?
self.match_token(
Token::Colon,
"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")?;
// 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)?;
// ebb-arg ::= Value(v) ":" Type(t) * arg-loc?
// ebb-param ::= Value(v) ":" Type(t) * arg-loc?
if self.optional(Token::LBracket) {
let loc = self.parse_value_location(ctx)?;
ctx.function.locations[value] = loc;
@@ -2473,10 +2473,10 @@ mod tests {
let mut ebbs = func.layout.ebbs();
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_args = func.dfg.ebb_args(ebb4);
let ebb4_args = func.dfg.ebb_params(ebb4);
assert_eq!(ebb4_args.len(), 1);
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 } => {
let next = builder.create_ebb();
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));
}
@@ -129,7 +129,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let loop_body = builder.create_ebb();
let next = builder.create_ebb();
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, &[]);
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
// instruction will be changed later when we translate the Else operator.
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));
}
@@ -190,7 +190,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
}
state.stack.truncate(frame.original_stack_size());
state.stack.extend_from_slice(
builder.ebb_args(frame.following_code()),
builder.ebb_params(frame.following_code()),
);
}
/**************************** 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
// (which corresponds to testing if the stack depth is 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;
}