Use PackedOption<Inst> in the Layout implementation.

This also revealed that the last_inst() method should return an Option.
This commit is contained in:
Jakob Stoklund Olesen
2017-01-19 14:26:47 -08:00
parent 52db486500
commit 3fc0f80223
2 changed files with 42 additions and 45 deletions

View File

@@ -5,9 +5,9 @@
use std::cmp; use std::cmp;
use std::iter::{Iterator, IntoIterator}; use std::iter::{Iterator, IntoIterator};
use entity_map::{EntityMap, EntityRef}; use entity_map::EntityMap;
use packed_option::PackedOption; use packed_option::PackedOption;
use ir::entities::{Ebb, Inst, NO_INST}; use ir::entities::{Ebb, Inst};
use ir::progpoint::{ProgramOrder, ExpandedProgramPoint}; use ir::progpoint::{ProgramOrder, ExpandedProgramPoint};
/// The `Layout` struct determines the layout of EBBs and instructions in a function. It does not /// The `Layout` struct determines the layout of EBBs and instructions in a function. It does not
@@ -30,7 +30,7 @@ pub struct Layout {
ebbs: EntityMap<Ebb, EbbNode>, ebbs: EntityMap<Ebb, EbbNode>,
// Linked list nodes for the layout order of instructions. Forms a double linked list per EBB, // Linked list nodes for the layout order of instructions. Forms a double linked list per EBB,
// terminated in both ends by NO_INST. // terminated in both ends by `None`.
insts: EntityMap<Inst, InstNode>, insts: EntityMap<Inst, InstNode>,
// First EBB in the layout order, or `None` when no EBBs have been laid out. // First EBB in the layout order, or `None` when no EBBs have been laid out.
@@ -120,7 +120,6 @@ impl Layout {
// Get the seq of the last instruction if it exists, otherwise use the EBB header seq. // Get the seq of the last instruction if it exists, otherwise use the EBB header seq.
self.ebbs[ebb] self.ebbs[ebb]
.last_inst .last_inst
.wrap()
.map(|inst| self.insts[inst].seq) .map(|inst| self.insts[inst].seq)
.unwrap_or(self.ebbs[ebb].seq) .unwrap_or(self.ebbs[ebb].seq)
} }
@@ -134,7 +133,7 @@ impl Layout {
let prev_seq = self.ebbs[ebb].prev.map(|prev_ebb| self.last_ebb_seq(prev_ebb)).unwrap_or(0); let prev_seq = self.ebbs[ebb].prev.map(|prev_ebb| self.last_ebb_seq(prev_ebb)).unwrap_or(0);
// Get the sequence number immediately following `ebb`. // Get the sequence number immediately following `ebb`.
let next_seq = if let Some(inst) = self.ebbs[ebb].first_inst.wrap() { let next_seq = if let Some(inst) = self.ebbs[ebb].first_inst.expand() {
self.insts[inst].seq self.insts[inst].seq
} else if let Some(next_ebb) = self.ebbs[ebb].next.expand() { } else if let Some(next_ebb) = self.ebbs[ebb].next.expand() {
self.ebbs[next_ebb].seq self.ebbs[next_ebb].seq
@@ -159,13 +158,13 @@ impl Layout {
let ebb = self.inst_ebb(inst).expect("inst must be inserted before assigning an seq"); let ebb = self.inst_ebb(inst).expect("inst must be inserted before assigning an seq");
// Get the sequence number immediately before `inst`. // Get the sequence number immediately before `inst`.
let prev_seq = match self.insts[inst].prev.wrap() { let prev_seq = match self.insts[inst].prev.expand() {
Some(prev_inst) => self.insts[prev_inst].seq, Some(prev_inst) => self.insts[prev_inst].seq,
None => self.ebbs[ebb].seq, None => self.ebbs[ebb].seq,
}; };
// Get the sequence number immediately following `inst`. // Get the sequence number immediately following `inst`.
let next_seq = if let Some(next_inst) = self.insts[inst].next.wrap() { let next_seq = if let Some(next_inst) = self.insts[inst].next.expand() {
self.insts[next_inst].seq self.insts[next_inst].seq
} else if let Some(next_ebb) = self.ebbs[ebb].next.expand() { } else if let Some(next_ebb) = self.ebbs[ebb].next.expand() {
self.ebbs[next_ebb].seq self.ebbs[next_ebb].seq
@@ -197,7 +196,7 @@ impl Layout {
self.insts[inst].seq = seq; self.insts[inst].seq = seq;
// Next instruction. // Next instruction.
inst = match self.insts[inst].next.wrap() { inst = match self.insts[inst].next.expand() {
None => return Some(seq), None => return Some(seq),
Some(next) => next, Some(next) => next,
}; };
@@ -221,7 +220,7 @@ impl Layout {
self.ebbs[ebb].seq = seq; self.ebbs[ebb].seq = seq;
// Renumber instructions in `ebb`. Stop when the numbers catch up. // Renumber instructions in `ebb`. Stop when the numbers catch up.
if let Some(inst) = self.ebbs[ebb].first_inst.wrap() { if let Some(inst) = self.ebbs[ebb].first_inst.expand() {
seq = match self.renumber_insts(inst, seq + MINOR_STRIDE) { seq = match self.renumber_insts(inst, seq + MINOR_STRIDE) {
Some(s) => s, Some(s) => s,
None => return, None => return,
@@ -276,7 +275,7 @@ impl Layout {
"Cannot append EBB that is already in the layout"); "Cannot append EBB that is already in the layout");
{ {
let node = self.ebbs.ensure(ebb); let node = self.ebbs.ensure(ebb);
assert!(node.first_inst == NO_INST && node.last_inst == NO_INST); assert!(node.first_inst.is_none() && node.last_inst.is_none());
node.prev = self.last_ebb.into(); node.prev = self.last_ebb.into();
node.next = None.into(); node.next = None.into();
} }
@@ -348,8 +347,8 @@ impl Layout {
struct EbbNode { struct EbbNode {
prev: PackedOption<Ebb>, prev: PackedOption<Ebb>,
next: PackedOption<Ebb>, next: PackedOption<Ebb>,
first_inst: Inst, first_inst: PackedOption<Inst>,
last_inst: Inst, last_inst: PackedOption<Inst>,
seq: SequenceNumber, seq: SequenceNumber,
} }
@@ -408,21 +407,21 @@ impl Layout {
let inst_node = self.insts.ensure(inst); let inst_node = self.insts.ensure(inst);
inst_node.ebb = ebb.into(); inst_node.ebb = ebb.into();
inst_node.prev = ebb_node.last_inst; inst_node.prev = ebb_node.last_inst;
assert_eq!(inst_node.next, NO_INST); assert!(inst_node.next.is_none());
} }
if ebb_node.first_inst == NO_INST { if ebb_node.first_inst.is_none() {
ebb_node.first_inst = inst; ebb_node.first_inst = inst.into();
} else { } else {
self.insts[ebb_node.last_inst].next = inst; self.insts[ebb_node.last_inst.unwrap()].next = inst.into();
} }
ebb_node.last_inst = inst; ebb_node.last_inst = inst.into();
} }
self.assign_inst_seq(inst); self.assign_inst_seq(inst);
} }
/// Fetch an ebb's last instruction. /// Fetch an ebb's last instruction.
pub fn last_inst(&self, ebb: Ebb) -> Inst { pub fn last_inst(&self, ebb: Ebb) -> Option<Inst> {
self.ebbs[ebb].last_inst self.ebbs[ebb].last_inst.into()
} }
/// Insert `inst` before the instruction `before` in the same EBB. /// Insert `inst` before the instruction `before` in the same EBB.
@@ -434,14 +433,13 @@ impl Layout {
{ {
let inst_node = self.insts.ensure(inst); let inst_node = self.insts.ensure(inst);
inst_node.ebb = ebb.into(); inst_node.ebb = ebb.into();
inst_node.next = before; inst_node.next = before.into();
inst_node.prev = after; inst_node.prev = after;
} }
self.insts[before].prev = inst; self.insts[before].prev = inst.into();
if after == NO_INST { match after.expand() {
self.ebbs[ebb].first_inst = inst; None => self.ebbs[ebb].first_inst = inst.into(),
} else { Some(a) => self.insts[a].next = inst.into(),
self.insts[after].next = inst;
} }
self.assign_inst_seq(inst); self.assign_inst_seq(inst);
} }
@@ -450,8 +448,8 @@ impl Layout {
pub fn ebb_insts<'f>(&'f self, ebb: Ebb) -> Insts<'f> { pub fn ebb_insts<'f>(&'f self, ebb: Ebb) -> Insts<'f> {
Insts { Insts {
layout: self, layout: self,
head: self.ebbs[ebb].first_inst.wrap(), head: self.ebbs[ebb].first_inst.into(),
tail: self.ebbs[ebb].last_inst.wrap(), tail: self.ebbs[ebb].last_inst.into(),
} }
} }
@@ -489,7 +487,7 @@ impl Layout {
let node = self.ebbs.ensure(new_ebb); let node = self.ebbs.ensure(new_ebb);
node.prev = old_ebb.into(); node.prev = old_ebb.into();
node.next = next_ebb; node.next = next_ebb;
node.first_inst = before; node.first_inst = before.into();
node.last_inst = last_inst; node.last_inst = last_inst;
} }
self.ebbs[old_ebb].next = new_ebb.into(); self.ebbs[old_ebb].next = new_ebb.into();
@@ -503,20 +501,19 @@ impl Layout {
// Disconnect the instruction links. // Disconnect the instruction links.
let prev_inst = self.insts[before].prev; let prev_inst = self.insts[before].prev;
self.insts[before].prev = NO_INST; self.insts[before].prev = None.into();
self.ebbs[old_ebb].last_inst = prev_inst; self.ebbs[old_ebb].last_inst = prev_inst;
if prev_inst == NO_INST { match prev_inst.expand() {
self.ebbs[old_ebb].first_inst = NO_INST; None => self.ebbs[old_ebb].first_inst = None.into(),
} else { Some(pi) => self.insts[pi].next = None.into(),
self.insts[prev_inst].next = NO_INST;
} }
// Fix the instruction -> ebb pointers. // Fix the instruction -> ebb pointers.
let mut i = before; let mut opt_i = Some(before);
while i != NO_INST { while let Some(i) = opt_i {
debug_assert_eq!(self.insts[i].ebb.expand(), Some(old_ebb)); debug_assert_eq!(self.insts[i].ebb.expand(), Some(old_ebb));
self.insts[i].ebb = new_ebb.into(); self.insts[i].ebb = new_ebb.into();
i = self.insts[i].next; opt_i = self.insts[i].next.into();
} }
self.assign_ebb_seq(new_ebb); self.assign_ebb_seq(new_ebb);
@@ -527,8 +524,8 @@ impl Layout {
struct InstNode { struct InstNode {
// The Ebb containing this instruction, or `None` if the instruction is not yet inserted. // The Ebb containing this instruction, or `None` if the instruction is not yet inserted.
ebb: PackedOption<Ebb>, ebb: PackedOption<Ebb>,
prev: Inst, prev: PackedOption<Inst>,
next: Inst, next: PackedOption<Inst>,
seq: SequenceNumber, seq: SequenceNumber,
} }
@@ -549,7 +546,7 @@ impl<'f> Iterator for Insts<'f> {
self.head = None; self.head = None;
self.tail = None; self.tail = None;
} else { } else {
self.head = Some(self.layout.insts[inst].next); self.head = self.layout.insts[inst].next.into();
} }
} }
rval rval
@@ -564,7 +561,7 @@ impl<'f> DoubleEndedIterator for Insts<'f> {
self.head = None; self.head = None;
self.tail = None; self.tail = None;
} else { } else {
self.tail = Some(self.layout.insts[inst].prev); self.tail = self.layout.insts[inst].prev.into();
} }
} }
rval rval
@@ -775,7 +772,7 @@ impl<'f> Cursor<'f> {
match self.pos { match self.pos {
Nowhere | After(..) => None, Nowhere | After(..) => None,
At(inst) => { At(inst) => {
if let Some(next) = self.layout.insts[inst].next.wrap() { if let Some(next) = self.layout.insts[inst].next.expand() {
self.pos = At(next); self.pos = At(next);
Some(next) Some(next)
} else { } else {
@@ -785,7 +782,7 @@ impl<'f> Cursor<'f> {
} }
} }
Before(ebb) => { Before(ebb) => {
if let Some(next) = self.layout.ebbs[ebb].first_inst.wrap() { if let Some(next) = self.layout.ebbs[ebb].first_inst.expand() {
self.pos = At(next); self.pos = At(next);
Some(next) Some(next)
} else { } else {
@@ -826,7 +823,7 @@ impl<'f> Cursor<'f> {
match self.pos { match self.pos {
Nowhere | Before(..) => None, Nowhere | Before(..) => None,
At(inst) => { At(inst) => {
if let Some(prev) = self.layout.insts[inst].prev.wrap() { if let Some(prev) = self.layout.insts[inst].prev.expand() {
self.pos = At(prev); self.pos = At(prev);
Some(prev) Some(prev)
} else { } else {
@@ -836,7 +833,7 @@ impl<'f> Cursor<'f> {
} }
} }
After(ebb) => { After(ebb) => {
if let Some(prev) = self.layout.ebbs[ebb].last_inst.wrap() { if let Some(prev) = self.layout.ebbs[ebb].last_inst.expand() {
self.pos = At(prev); self.pos = At(prev);
Some(prev) Some(prev)
} else { } else {

View File

@@ -110,7 +110,7 @@ impl<'a> Verifier<'a> {
fn ebb_integrity(&self, ebb: Ebb, inst: Inst) -> Result<()> { fn ebb_integrity(&self, ebb: Ebb, inst: Inst) -> Result<()> {
let is_terminator = self.func.dfg[inst].opcode().is_terminator(); let is_terminator = self.func.dfg[inst].opcode().is_terminator();
let is_last_inst = self.func.layout.last_inst(ebb) == inst; let is_last_inst = self.func.layout.last_inst(ebb) == Some(inst);
if is_terminator && !is_last_inst { if is_terminator && !is_last_inst {
// Terminating instructions only occur at the end of blocks. // Terminating instructions only occur at the end of blocks.