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:
13
cranelift/docs/callex.cton
Normal file
13
cranelift/docs/callex.cton
Normal 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
|
||||||
|
}
|
||||||
@@ -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:
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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()`.
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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)| {
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user