Convert the Branch and Jump instruction formats to value_list.

The Branch format also stores its fixed argument in the value list. This
requires the value pool to be passed to a few more functions.

Note that this actually makes the Branch and Jump variants of
InstructionData identical. The instruction format hashing does not yet
understand that all value operands are stored in the value list. We'll
fix that in a later patch.

Also convert IndirectCall, noting that Call and IndirectCall remain
separate instruction formats because they have different immediate
fields.
This commit is contained in:
Jakob Stoklund Olesen
2017-03-09 14:53:31 -08:00
parent 364b8e5f0a
commit 1135a89af9
9 changed files with 88 additions and 141 deletions

View File

@@ -196,12 +196,14 @@ pub enum InstructionData {
Jump {
opcode: Opcode,
ty: Type,
data: Box<JumpData>,
destination: Ebb,
args: ValueList,
},
Branch {
opcode: Opcode,
ty: Type,
data: Box<BranchData>,
destination: Ebb,
args: ValueList,
},
BranchTable {
opcode: Opcode,
@@ -220,7 +222,8 @@ pub enum InstructionData {
opcode: Opcode,
ty: Type,
second_result: PackedOption<Value>,
data: Box<IndirectCallData>,
sig_ref: SigRef,
args: ValueList,
},
Return {
opcode: Opcode,
@@ -255,9 +258,10 @@ impl VariableArgs {
self.0.is_empty()
}
/// Convert this to a value list in `pool`.
pub fn into_value_list(self, pool: &mut ValueListPool) -> ValueList {
/// Convert this to a value list in `pool` with `fixed` prepended.
pub fn into_value_list(self, fixed: &[Value], pool: &mut ValueListPool) -> ValueList {
let mut vlist = ValueList::default();
vlist.extend(fixed.iter().cloned(), pool);
vlist.extend(self.0, pool);
vlist
}
@@ -327,85 +331,6 @@ impl Display for TernaryOverflowData {
}
}
/// Payload data for jump instructions. These need to carry lists of EBB arguments that won't fit
/// in the allowed `InstructionData` size.
#[derive(Clone, Debug)]
pub struct JumpData {
/// Jump destination EBB.
pub destination: Ebb,
/// Arguments passed to destination EBB.
pub varargs: VariableArgs,
}
impl Display for JumpData {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.varargs.is_empty() {
write!(f, "{}", self.destination)
} else {
write!(f, "{}({})", self.destination, self.varargs)
}
}
}
/// Payload data for branch instructions. These need to carry lists of EBB arguments that won't fit
/// in the allowed `InstructionData` size.
#[derive(Clone, Debug)]
pub struct BranchData {
/// Value argument controlling the branch.
pub arg: Value,
/// Branch destination EBB.
pub destination: Ebb,
/// Arguments passed to destination EBB.
pub varargs: VariableArgs,
}
impl BranchData {
/// Get references to the arguments.
pub fn arguments(&self) -> [&[Value]; 2] {
[ref_slice(&self.arg), &self.varargs]
}
/// Get mutable references to the arguments.
pub fn arguments_mut(&mut self) -> [&mut [Value]; 2] {
[ref_slice_mut(&mut self.arg), &mut self.varargs]
}
}
impl Display for BranchData {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}, {}", self.arg, self.destination)?;
if !self.varargs.is_empty() {
write!(f, "({})", self.varargs)?;
}
Ok(())
}
}
/// Payload of an indirect call instruction.
#[derive(Clone, Debug)]
pub struct IndirectCallData {
/// Callee function.
pub arg: Value,
/// Signature of the callee function.
pub sig_ref: SigRef,
/// Dynamically sized array containing call argument values.
pub varargs: VariableArgs,
}
impl IndirectCallData {
/// Get references to the arguments.
pub fn arguments(&self) -> [&[Value]; 2] {
[ref_slice(&self.arg), &self.varargs]
}
/// Get mutable references to the arguments.
pub fn arguments_mut(&mut self) -> [&mut [Value]; 2] {
[ref_slice_mut(&mut self.arg), &mut self.varargs]
}
}
/// Payload of a return instruction.
#[derive(Clone, Debug)]
pub struct ReturnData {
@@ -467,13 +392,13 @@ impl InstructionData {
///
/// Any instruction that can transfer control to another EBB reveals its possible destinations
/// here.
pub fn analyze_branch<'a>(&'a self) -> BranchInfo<'a> {
pub fn analyze_branch<'a>(&'a self, pool: &'a ValueListPool) -> BranchInfo<'a> {
match self {
&InstructionData::Jump { ref data, .. } => {
BranchInfo::SingleDest(data.destination, &data.varargs)
&InstructionData::Jump { destination, ref args, .. } => {
BranchInfo::SingleDest(destination, &args.as_slice(pool))
}
&InstructionData::Branch { ref data, .. } => {
BranchInfo::SingleDest(data.destination, &data.varargs)
&InstructionData::Branch { destination, ref args, .. } => {
BranchInfo::SingleDest(destination, &args.as_slice(pool)[1..])
}
&InstructionData::BranchTable { table, .. } => BranchInfo::Table(table),
_ => BranchInfo::NotABranch,
@@ -488,8 +413,8 @@ impl InstructionData {
&InstructionData::Call { func_ref, ref args, .. } => {
CallInfo::Direct(func_ref, &args.as_slice(pool))
}
&InstructionData::IndirectCall { ref data, .. } => {
CallInfo::Indirect(data.sig_ref, &data.varargs)
&InstructionData::IndirectCall { sig_ref, ref args, .. } => {
CallInfo::Indirect(sig_ref, &args.as_slice(pool))
}
_ => CallInfo::NotACall,
}
@@ -507,7 +432,7 @@ impl InstructionData {
} else if constraints.requires_typevar_operand() {
// Not all instruction formats have a designated operand, but in that case
// `requires_typevar_operand()` should never be true.
dfg.value_type(self.typevar_operand()
dfg.value_type(self.typevar_operand(&dfg.value_lists)
.expect("Instruction format doesn't have a designated operand, bad opcode."))
} else {
// For locality of reference, we prefer to get the controlling type variable from