Skip to content
This repository has been archived by the owner on Oct 4, 2022. It is now read-only.

Commit

Permalink
Add orig_insn_map: mapping from new to original insn indices.
Browse files Browse the repository at this point in the history
This is needed in the Cranelift client code in order to track
source-location mapping for debug info: we need to be able to shuffle
the source locations into the new locations after the regalloc has done
its instruction-stream editing. The `target_map` result is not quite
good enough, because it only provides old --> new mappings at a basic
block granularity.

This commit also adds "invalid" values to the index types; this is
useful to represent "new instruction maps to no old instruction" without
the memory-layout waste of an `Option<u32>`.
  • Loading branch information
cfallin committed Apr 24, 2020
1 parent 497c2ed commit b349cfa
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 17 deletions.
18 changes: 9 additions & 9 deletions lib/src/backtracking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ impl SpillSlotAllocator {
self.slots.push(LogicalSpillSlot::Unavail);
}
// And now the new slot.
let dflt = RangeFragIx::new(0xFFFF_FFFF); // value is unimportant
let dflt = RangeFragIx::invalid_value();
let tree = AVLTree::<RangeFragIx>::new(dflt);
let res = self.slots.len() as u32;
self.slots.push(LogicalSpillSlot::InUse {
Expand Down Expand Up @@ -1108,12 +1108,11 @@ fn cmp_tree_entries_for_CommitmentMapFAST(
impl CommitmentMapFAST {
pub fn new() -> Self {
// The AVL tree constructor needs a default value for the elements. It
// will never be used. To be on the safe side, give it something that
// will show as obviously bogus if we ever try to "dereference" any part
// of it.
// will never be used. The not-present index value will show as
// obviously bogus if we ever try to "dereference" any part of it.
let dflt = FIxAndVLRIx::new(
RangeFragIx::new(0xFFFF_FFFF),
Some(VirtualRangeIx::new(0xFFFF_FFFF)),
RangeFragIx::invalid_value(),
Some(VirtualRangeIx::invalid_value()),
);
Self {
tree: AVLTree::<FIxAndVLRIx>::new(dflt),
Expand Down Expand Up @@ -1740,7 +1739,7 @@ fn frags_are_mergeable(frag1: &RangeFrag, frag2: &RangeFrag) -> bool {
false
}

const Z_INVALID_BLOCKIX: BlockIx = BlockIx::BlockIx(0xFFFF_FFFF);
const Z_INVALID_BLOCKIX: BlockIx = BlockIx::invalid_value();
const Z_INVALID_COUNT: u16 = 0xFFFF;

// Try and compress the fragments for each virtual range in `vlr_env`, adding
Expand Down Expand Up @@ -2803,7 +2802,7 @@ pub fn alloc_main<F: Function>(
// ======== BEGIN Create the RegAllocResult ========

match final_insns_and_targetmap__or_err {
Ok((ref final_insns, ref _targetmap)) => {
Ok((ref final_insns, ..)) => {
info!(
"alloc_main: out: VLRs: {} initially, {} processed",
num_vlrs_initial, num_vlrs_processed
Expand All @@ -2829,7 +2828,7 @@ pub fn alloc_main<F: Function>(
}
}

let (final_insns, target_map) = match final_insns_and_targetmap__or_err {
let (final_insns, target_map, orig_insn_map) = match final_insns_and_targetmap__or_err {
Err(e) => {
info!("alloc_main: fail");
return Err(e);
Expand Down Expand Up @@ -2891,6 +2890,7 @@ pub fn alloc_main<F: Function>(
let ra_res = RegAllocResult {
insns: final_insns,
target_map,
orig_insn_map,
clobbered_registers,
num_spill_slots: spill_slot_allocator.slots.len() as u32,
block_annotations,
Expand Down
35 changes: 31 additions & 4 deletions lib/src/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,61 +435,88 @@ macro_rules! generate_boilerplate {
#[allow(dead_code)]
#[inline(always)]
pub fn new(n: u32) -> Self {
debug_assert!(n != u32::max_value());
Self::$TypeIx(n)
}
#[allow(dead_code)]
#[inline(always)]
pub fn max_value() -> Self {
Self::$TypeIx(u32::max_value())
pub const fn max_value() -> Self {
Self::$TypeIx(u32::max_value() - 1)
}
#[allow(dead_code)]
#[inline(always)]
pub fn min_value() -> Self {
pub const fn min_value() -> Self {
Self::$TypeIx(u32::min_value())
}
#[allow(dead_code)]
#[inline(always)]
pub const fn invalid_value() -> Self {
Self::$TypeIx(u32::max_value())
}
#[allow(dead_code)]
#[inline(always)]
pub fn is_valid(self) -> bool {
self != Self::invalid_value()
}
#[allow(dead_code)]
#[inline(always)]
pub fn is_invalid(self) -> bool {
self == Self::invalid_value()
}
#[allow(dead_code)]
#[inline(always)]
pub fn get(self) -> u32 {
debug_assert!(self.is_valid());
match self {
$TypeIx::$TypeIx(n) => n,
}
}
#[allow(dead_code)]
#[inline(always)]
pub fn plus(self, delta: u32) -> $TypeIx {
debug_assert!(self.is_valid());
$TypeIx::$TypeIx(self.get() + delta)
}
#[allow(dead_code)]
#[inline(always)]
pub fn minus(self, delta: u32) -> $TypeIx {
debug_assert!(self.is_valid());
$TypeIx::$TypeIx(self.get() - delta)
}
#[allow(dead_code)]
pub fn dotdot(&self, last_plus1: $TypeIx) -> Range<$TypeIx> {
debug_assert!(self.is_valid());
let len = (last_plus1.get() - self.get()) as usize;
Range::new(*self, len)
}
}
impl fmt::Debug for $TypeIx {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}{}", $PrintingPrefix, &self.get())
if self.is_invalid() {
write!(fmt, "{}<NONE>", $PrintingPrefix)
} else {
write!(fmt, "{}{}", $PrintingPrefix, &self.get())
}
}
}
impl PlusOne for $TypeIx {
#[inline(always)]
fn plus_one(&self) -> Self {
debug_assert!(self.is_valid());
self.plus(1)
}
}
impl PlusN for $TypeIx {
#[inline(always)]
fn plus_n(&self, n: usize) -> Self {
debug_assert!(self.is_valid());
self.plus(n as u32)
}
}
impl Into<u32> for $TypeIx {
#[inline(always)]
fn into(self) -> u32 {
debug_assert!(self.is_valid());
self.get()
}
}
Expand Down
26 changes: 23 additions & 3 deletions lib/src/inst_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,14 @@ fn map_vregs_to_rregs<F: Function>(
fn add_spills_reloads_and_moves<F: Function>(
func: &mut F,
mut insts_to_add: Vec<InstToInsertAndPoint>,
) -> Result<(Vec<F::Inst>, TypedIxVec<BlockIx, InstIx>), String> {
) -> Result<
(
Vec<F::Inst>,
TypedIxVec<BlockIx, InstIx>,
TypedIxVec<InstIx, InstIx>,
),
String,
> {
// Construct the final code by interleaving the mapped code with the the
// spills, reloads and moves that we have been requested to insert. To do
// that requires having the latter sorted by InstPoint.
Expand All @@ -447,6 +454,9 @@ fn add_spills_reloads_and_moves<F: Function>(

let mut insns: Vec<F::Inst> = vec![];
let mut target_map: TypedIxVec<BlockIx, InstIx> = TypedIxVec::new();
let mut orig_insn_map: TypedIxVec<InstIx, InstIx> = TypedIxVec::new();
target_map.reserve(func.blocks().len());
orig_insn_map.reserve(func.insn_indices().len() + insts_to_add.len());

for iix in func.insn_indices() {
// Is `iix` the first instruction in a block? Meaning, are we
Expand All @@ -463,15 +473,18 @@ fn add_spills_reloads_and_moves<F: Function>(
&& insts_to_add[curITA].point == InstPoint::new_reload(iix)
{
insns.push(insts_to_add[curITA].inst.construct(func));
orig_insn_map.push(InstIx::invalid_value());
curITA += 1;
}
// Copy the inst at `iix` itself
orig_insn_map.push(iix);
insns.push(func.get_insn(iix).clone());
// And copy the extra insts that are to be placed at the spill point of
// `iix`.
while curITA < insts_to_add.len() && insts_to_add[curITA].point == InstPoint::new_spill(iix)
{
insns.push(insts_to_add[curITA].inst.construct(func));
orig_insn_map.push(InstIx::invalid_value());
curITA += 1;
}

Expand All @@ -485,7 +498,7 @@ fn add_spills_reloads_and_moves<F: Function>(
debug_assert!(curITA == insts_to_add.len());
debug_assert!(curB.get() == func.blocks().len() as u32);

Ok((insns, target_map))
Ok((insns, target_map, orig_insn_map))
}

//=============================================================================
Expand All @@ -501,7 +514,14 @@ pub(crate) fn edit_inst_stream<F: Function>(
reg_universe: &RealRegUniverse,
has_multiple_blocks_per_frag: bool,
use_checker: bool,
) -> Result<(Vec<F::Inst>, TypedIxVec<BlockIx, InstIx>), RegAllocError> {
) -> Result<
(
Vec<F::Inst>,
TypedIxVec<BlockIx, InstIx>,
TypedIxVec<InstIx, InstIx>,
),
RegAllocError,
> {
map_vregs_to_rregs(
func,
frag_map,
Expand Down
10 changes: 10 additions & 0 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,16 @@ pub struct RegAllocResult<F: Function> {
/// branch targets appropriately.
pub target_map: TypedIxVec<BlockIx, InstIx>,

/// Full mapping from new instruction indices to original instruction
/// indices. May be needed by the client to, for example, update metadata
/// such as debug/source-location info as the instructions are spliced
/// and reordered.
///
/// Each entry is an `InstIx`, but may be `InstIx::invalid_value()` if the
/// new instruction at this new index was inserted by the allocator
/// (i.e., if it is a load, spill or move instruction).
pub orig_insn_map: TypedIxVec</* new */ InstIx, /* orig */ InstIx>,

/// Which real registers were overwritten? This will contain all real regs
/// that appear as defs or modifies in register slots of the output
/// instruction list. This will only list registers that are available to
Expand Down
3 changes: 2 additions & 1 deletion lib/src/linear_scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3251,7 +3251,7 @@ fn apply_registers<F: Function>(
use_checker,
);

let (final_insns, target_map) = match final_insns_and_targetmap_or_err {
let (final_insns, target_map, orig_insn_map) = match final_insns_and_targetmap_or_err {
Err(e) => return Err(e),
Ok(pair) => pair,
};
Expand Down Expand Up @@ -3295,6 +3295,7 @@ fn apply_registers<F: Function>(
let ra_res = RegAllocResult {
insns: final_insns,
target_map,
orig_insn_map,
clobbered_registers,
num_spill_slots,
block_annotations: None,
Expand Down

0 comments on commit b349cfa

Please sign in to comment.