Add a func.inst_offsets() iterator.

This Function method can be used after the final code layout has been
computed. It returns all the instructions in an EBB along with their
encoded size and offset from the beginning of the function.

This is useful for extracting additional metadata about trapping
instructions and other things that may be needed by a VM.
This commit is contained in:
Jakob Stoklund Olesen
2018-02-01 17:10:21 -08:00
parent 429027e2f2
commit e3714ddd10
2 changed files with 48 additions and 3 deletions

View File

@@ -211,7 +211,8 @@ impl SubTest for TestBinEmit {
"Inconsistent {} header offset",
ebb
);
for inst in func.layout.ebb_insts(ebb) {
for (offset, inst, enc_bytes) in func.inst_offsets(ebb, &encinfo) {
assert_eq!(sink.offset, offset);
sink.text.clear();
let enc = func.encodings[inst];
@@ -234,7 +235,7 @@ impl SubTest for TestBinEmit {
// Verify the encoding recipe sizes against the ISAs emit_inst implementation.
assert_eq!(
emitted,
encinfo.bytes(enc),
enc_bytes,
"Inconsistent size for [{}] {}",
encinfo.display(enc),
func.dfg.display_inst(inst, isa)

View File

@@ -3,13 +3,14 @@
//! The `Function` struct defined in this module owns all of its extended basic blocks and
//! instructions.
use binemit::CodeOffset;
use entity::{PrimaryMap, EntityMap};
use ir;
use ir::{ExternalName, CallConv, Signature, DataFlowGraph, Layout};
use ir::{InstEncodings, ValueLocations, JumpTables, StackSlots, EbbOffsets, SourceLocs};
use ir::{Ebb, JumpTableData, JumpTable, StackSlotData, StackSlot, SigRef, ExtFuncData, FuncRef,
GlobalVarData, GlobalVar, HeapData, Heap};
use isa::TargetIsa;
use isa::{TargetIsa, EncInfo};
use std::fmt;
use write::write_function;
@@ -153,6 +154,28 @@ impl Function {
self.dfg.ebb_params(entry)[i]
})
}
/// Get an iterator over the instructions in `ebb`, including offsets and encoded instruction
/// sizes.
///
/// The iterator returns `(offset, inst, size)` tuples, where `offset` if the offset in bytes
/// from the beginning of the function to the instruction, and `size` is the size of the
/// instruction in bytes, or 0 for unencoded instructions.
///
/// This function can only be used after the code layout has been computed by the
/// `binemit::relax_branches()` function.
pub fn inst_offsets<'a>(&'a self, ebb: Ebb, encinfo: &EncInfo) -> InstOffsetIter<'a> {
assert!(
!self.offsets.is_empty(),
"Code layout must be computed first"
);
InstOffsetIter {
encinfo: encinfo.clone(),
encodings: &self.encodings,
offset: self.offsets[ebb],
iter: self.layout.ebb_insts(ebb),
}
}
}
/// Wrapper type capable of displaying a `Function` with correct ISA annotations.
@@ -175,3 +198,24 @@ impl fmt::Debug for Function {
write_function(fmt, self, None)
}
}
/// Iterator returning instruction offsets and sizes: `(offset, inst, size)`.
pub struct InstOffsetIter<'a> {
encinfo: EncInfo,
encodings: &'a InstEncodings,
offset: CodeOffset,
iter: ir::layout::Insts<'a>,
}
impl<'a> Iterator for InstOffsetIter<'a> {
type Item = (CodeOffset, ir::Inst, CodeOffset);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|inst| {
let size = self.encinfo.bytes(self.encodings[inst]);
let offset = self.offset;
self.offset += size;
(offset, inst, size)
})
}
}