Add an ISA argument to dfg.display_inst().

Include ISA-specific annotations in tracing and error messages.
This commit is contained in:
Jakob Stoklund Olesen
2017-07-12 10:12:20 -07:00
parent e4da2e1f22
commit 69f974ba5d
10 changed files with 42 additions and 33 deletions

View File

@@ -127,7 +127,7 @@ impl SubTest for TestBinEmit {
AnyEntity::Inst(inst) => { AnyEntity::Inst(inst) => {
if let Some(prev) = bins.insert(inst, want) { if let Some(prev) = bins.insert(inst, want) {
return Err(format!("multiple 'bin:' directives on {}: '{}' and '{}'", return Err(format!("multiple 'bin:' directives on {}: '{}' and '{}'",
func.dfg.display_inst(inst), func.dfg.display_inst(inst, isa),
prev, prev,
want)); want));
} }
@@ -166,7 +166,7 @@ impl SubTest for TestBinEmit {
encinfo.bytes(enc), encinfo.bytes(enc),
"Inconsistent size for [{}] {}", "Inconsistent size for [{}] {}",
encinfo.display(enc), encinfo.display(enc),
func.dfg.display_inst(inst)); func.dfg.display_inst(inst, isa));
} }
// Check against bin: directives. // Check against bin: directives.
@@ -174,13 +174,13 @@ impl SubTest for TestBinEmit {
if !enc.is_legal() { if !enc.is_legal() {
return Err(format!("{} can't be encoded: {}", return Err(format!("{} can't be encoded: {}",
inst, inst,
func.dfg.display_inst(inst))); func.dfg.display_inst(inst, isa)));
} }
let have = sink.text.trim(); let have = sink.text.trim();
if have != want { if have != want {
return Err(format!("Bad machine code for {}: {}\nWant: {}\nGot: {}", return Err(format!("Bad machine code for {}: {}\nWant: {}\nGot: {}",
inst, inst,
func.dfg.display_inst(inst), func.dfg.display_inst(inst, isa),
want, want,
have)); have));
} }

View File

@@ -42,7 +42,7 @@ pub fn pretty_verifier_error(func: &ir::Function,
let mut msg = err.to_string(); let mut msg = err.to_string();
match err.location { match err.location {
AnyEntity::Inst(inst) => { AnyEntity::Inst(inst) => {
write!(msg, "\n{}: {}\n\n", inst, func.dfg.display_inst(inst)).unwrap() write!(msg, "\n{}: {}\n\n", inst, func.dfg.display_inst(inst, isa)).unwrap()
} }
_ => msg.push('\n'), _ => msg.push('\n'),
} }

View File

@@ -53,5 +53,5 @@ pub trait CodeSink {
pub fn bad_encoding(func: &Function, inst: Inst) -> ! { pub fn bad_encoding(func: &Function, inst: Inst) -> ! {
panic!("Bad encoding {} for {}", panic!("Bad encoding {} for {}",
func.encodings[inst], func.encodings[inst],
func.dfg.display_inst(inst)); func.dfg.display_inst(inst, None));
} }

View File

@@ -135,7 +135,7 @@ fn relax_branch(dfg: &mut DataFlowGraph,
let inst = pos.current_inst().unwrap(); let inst = pos.current_inst().unwrap();
dbg!("Relaxing [{}] {} for {:#x}-{:#x} range", dbg!("Relaxing [{}] {} for {:#x}-{:#x} range",
encinfo.display(encodings[inst]), encinfo.display(encodings[inst]),
dfg.display_inst(inst), dfg.display_inst(inst, None),
offset, offset,
dest_offset); dest_offset);
unimplemented!(); unimplemented!();

View File

@@ -1,6 +1,7 @@
//! Data flow graph tracking Instructions, Values, and EBBs. //! Data flow graph tracking Instructions, Values, and EBBs.
use entity_map::{EntityMap, PrimaryEntityData}; use entity_map::{EntityMap, PrimaryEntityData};
use isa::TargetIsa;
use ir::builder::{InsertBuilder, ReplaceBuilder}; use ir::builder::{InsertBuilder, ReplaceBuilder};
use ir::extfunc::ExtFuncData; use ir::extfunc::ExtFuncData;
use ir::instructions::{Opcode, InstructionData, CallInfo}; use ir::instructions::{Opcode, InstructionData, CallInfo};
@@ -162,7 +163,7 @@ impl DataFlowGraph {
self.results[inst].get(num as usize, &self.value_lists), self.results[inst].get(num as usize, &self.value_lists),
"Dangling result value {}: {}", "Dangling result value {}: {}",
v, v,
self.display_inst(inst)); self.display_inst(inst, None));
ValueDef::Res(inst, num as usize) ValueDef::Res(inst, num as usize)
} }
ValueData::Arg { ebb, num, .. } => { ValueData::Arg { ebb, num, .. } => {
@@ -376,8 +377,11 @@ impl DataFlowGraph {
} }
/// Returns an object that displays `inst`. /// Returns an object that displays `inst`.
pub fn display_inst(&self, inst: Inst) -> DisplayInst { pub fn display_inst<'a, I: Into<Option<&'a TargetIsa>>>(&'a self,
DisplayInst(self, inst) inst: Inst,
isa: I)
-> DisplayInst<'a> {
DisplayInst(self, isa.into(), inst)
} }
/// Get all value arguments on `inst` as a slice. /// Get all value arguments on `inst` as a slice.
@@ -552,7 +556,7 @@ impl DataFlowGraph {
old_value, old_value,
"{} wasn't detached from {}", "{} wasn't detached from {}",
old_value, old_value,
self.display_inst(inst)); self.display_inst(inst, None));
new_value new_value
} }
@@ -830,14 +834,15 @@ impl EbbData {
} }
/// Object that can display an instruction. /// Object that can display an instruction.
pub struct DisplayInst<'a>(&'a DataFlowGraph, Inst); pub struct DisplayInst<'a>(&'a DataFlowGraph, Option<&'a TargetIsa>, Inst);
impl<'a> fmt::Display for DisplayInst<'a> { impl<'a> fmt::Display for DisplayInst<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let dfg = self.0; let dfg = self.0;
let inst = &dfg[self.1]; let isa = self.1;
let inst = self.2;
if let Some((first, rest)) = dfg.inst_results(self.1).split_first() { if let Some((first, rest)) = dfg.inst_results(inst).split_first() {
write!(f, "{}", first)?; write!(f, "{}", first)?;
for v in rest { for v in rest {
write!(f, ", {}", v)?; write!(f, ", {}", v)?;
@@ -846,13 +851,13 @@ impl<'a> fmt::Display for DisplayInst<'a> {
} }
let typevar = dfg.ctrl_typevar(self.1); let typevar = dfg.ctrl_typevar(inst);
if typevar.is_void() { if typevar.is_void() {
write!(f, "{}", inst.opcode())?; write!(f, "{}", dfg[inst].opcode())?;
} else { } else {
write!(f, "{}.{}", inst.opcode(), typevar)?; write!(f, "{}.{}", dfg[inst].opcode(), typevar)?;
} }
write_operands(f, dfg, None, self.1) write_operands(f, dfg, isa, inst)
} }
} }
@@ -870,7 +875,7 @@ mod tests {
let inst = dfg.make_inst(idata); let inst = dfg.make_inst(idata);
dfg.make_inst_results(inst, types::I32); dfg.make_inst_results(inst, types::I32);
assert_eq!(inst.to_string(), "inst0"); assert_eq!(inst.to_string(), "inst0");
assert_eq!(dfg.display_inst(inst).to_string(), "v0 = iconst.i32"); assert_eq!(dfg.display_inst(inst, None).to_string(), "v0 = iconst.i32");
// Immutable reference resolution. // Immutable reference resolution.
{ {
@@ -902,7 +907,7 @@ mod tests {
let idata = InstructionData::Nullary { opcode: Opcode::Trap }; let idata = InstructionData::Nullary { opcode: Opcode::Trap };
let inst = dfg.make_inst(idata); let inst = dfg.make_inst(idata);
assert_eq!(dfg.display_inst(inst).to_string(), "trap"); assert_eq!(dfg.display_inst(inst, None).to_string(), "trap");
// Result slice should be empty. // Result slice should be empty.
assert_eq!(dfg.inst_results(inst), &[]); assert_eq!(dfg.inst_results(inst), &[]);

View File

@@ -474,7 +474,7 @@ pub fn handle_call_abi(dfg: &mut DataFlowGraph, cfg: &ControlFlowGraph, pos: &mu
debug_assert!(check_call_signature(dfg, inst).is_ok(), debug_assert!(check_call_signature(dfg, inst).is_ok(),
"Signature still wrong: {}, {}{}", "Signature still wrong: {}, {}{}",
dfg.display_inst(inst), dfg.display_inst(inst, None),
sig_ref, sig_ref,
dfg.signatures[sig_ref]); dfg.signatures[sig_ref]);
@@ -523,7 +523,7 @@ pub fn handle_return_abi(dfg: &mut DataFlowGraph,
if special_args > 0 { if special_args > 0 {
dbg!("Adding {} special-purpose arguments to {}", dbg!("Adding {} special-purpose arguments to {}",
special_args, special_args,
dfg.display_inst(inst)); dfg.display_inst(inst, None));
let mut vlist = dfg[inst].take_value_list().unwrap(); let mut vlist = dfg[inst].take_value_list().unwrap();
for arg in &sig.return_types[abi_args..] { for arg in &sig.return_types[abi_args..] {
match arg.purpose { match arg.purpose {
@@ -550,7 +550,7 @@ pub fn handle_return_abi(dfg: &mut DataFlowGraph,
debug_assert!(check_return_signature(dfg, inst, sig), debug_assert!(check_return_signature(dfg, inst, sig),
"Signature still wrong: {} / signature {}", "Signature still wrong: {} / signature {}",
dfg.display_inst(inst), dfg.display_inst(inst, None),
sig); sig);
// Yes, we changed stuff. // Yes, we changed stuff.

View File

@@ -123,7 +123,7 @@ fn split_any(dfg: &mut DataFlowGraph,
let branch_opc = dfg[inst].opcode(); let branch_opc = dfg[inst].opcode();
assert!(branch_opc.is_branch(), assert!(branch_opc.is_branch(),
"Predecessor not a branch: {}", "Predecessor not a branch: {}",
dfg.display_inst(inst)); dfg.display_inst(inst, None));
let fixed_args = branch_opc.constraints().fixed_value_arguments(); let fixed_args = branch_opc.constraints().fixed_value_arguments();
let mut args = dfg[inst] let mut args = dfg[inst]
.take_value_list() .take_value_list()

View File

@@ -399,7 +399,7 @@ impl<'a> Context<'a> {
dbg!("Checking {}: {}: {}", dbg!("Checking {}: {}: {}",
pred_val, pred_val,
pred_ebb, pred_ebb,
self.func.dfg.display_inst(pred_inst)); self.func.dfg.display_inst(pred_inst, self.isa));
// 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
@@ -474,9 +474,9 @@ impl<'a> Context<'a> {
let ty = self.func.dfg.value_type(copy); let ty = self.func.dfg.value_type(copy);
dbg!("Inserted {}, before {}: {}", dbg!("Inserted {}, before {}: {}",
self.func.dfg.display_inst(inst), self.func.dfg.display_inst(inst, self.isa),
pred_ebb, pred_ebb,
self.func.dfg.display_inst(pred_inst)); self.func.dfg.display_inst(pred_inst, self.isa));
// Give it an encoding. // Give it an encoding.
let encoding = self.isa let encoding = self.isa
@@ -519,7 +519,7 @@ impl<'a> Context<'a> {
self.liveness.move_def_locally(succ_val, inst); self.liveness.move_def_locally(succ_val, inst);
dbg!("Inserted {}, following {}({}: {})", dbg!("Inserted {}, following {}({}: {})",
self.func.dfg.display_inst(inst), self.func.dfg.display_inst(inst, self.isa),
ebb, ebb,
new_val, new_val,
ty); ty);

View File

@@ -73,6 +73,7 @@ pub struct Coloring {
/// Immutable context information and mutable references that don't need to be borrowed across /// Immutable context information and mutable references that don't need to be borrowed across
/// method calls should go in this struct. /// method calls should go in this struct.
struct Context<'a> { struct Context<'a> {
isa: &'a TargetIsa,
// Cached ISA information. // Cached ISA information.
// We save it here to avoid frequent virtual function calls on the `TargetIsa` trait object. // We save it here to avoid frequent virtual function calls on the `TargetIsa` trait object.
reginfo: RegInfo, reginfo: RegInfo,
@@ -111,6 +112,7 @@ impl Coloring {
tracker: &mut LiveValueTracker) { tracker: &mut LiveValueTracker) {
dbg!("Coloring for:\n{}", func.display(isa)); dbg!("Coloring for:\n{}", func.display(isa));
let mut ctx = Context { let mut ctx = Context {
isa,
reginfo: isa.register_info(), reginfo: isa.register_info(),
encinfo: isa.encoding_info(), encinfo: isa.encoding_info(),
domtree, domtree,
@@ -279,7 +281,7 @@ impl<'a> Context<'a> {
locations: &mut ValueLocations, locations: &mut ValueLocations,
func_signature: &Signature) { func_signature: &Signature) {
dbg!("Coloring {}\n {}", dbg!("Coloring {}\n {}",
dfg.display_inst(inst), dfg.display_inst(inst, self.isa),
regs.display(&self.reginfo)); regs.display(&self.reginfo));
// EBB whose arguments should be colored to match the current branch instruction's // EBB whose arguments should be colored to match the current branch instruction's
@@ -308,7 +310,7 @@ impl<'a> Context<'a> {
assert_eq!(dfg.inst_variable_args(inst).len(), assert_eq!(dfg.inst_variable_args(inst).len(),
0, 0,
"Can't handle EBB arguments: {}", "Can't handle EBB arguments: {}",
dfg.display_inst(inst)); dfg.display_inst(inst, self.isa));
self.undivert_regs(|lr| !lr.is_local()); self.undivert_regs(|lr| !lr.is_local());
} }
} }

View File

@@ -246,7 +246,9 @@ impl<'a> Context<'a> {
pos: &mut Cursor, pos: &mut Cursor,
dfg: &mut DataFlowGraph, dfg: &mut DataFlowGraph,
tracker: &mut LiveValueTracker) { tracker: &mut LiveValueTracker) {
dbg!("Inst {}, {}", dfg.display_inst(inst), self.pressure); dbg!("Inst {}, {}",
dfg.display_inst(inst, self.isa),
self.pressure);
// We may need to resolve register constraints if there are any noteworthy uses. // We may need to resolve register constraints if there are any noteworthy uses.
assert!(self.reg_uses.is_empty()); assert!(self.reg_uses.is_empty());
@@ -292,7 +294,7 @@ impl<'a> Context<'a> {
None => { None => {
panic!("Ran out of {} registers for {}", panic!("Ran out of {} registers for {}",
op.regclass, op.regclass,
dfg.display_inst(inst)) dfg.display_inst(inst, self.isa))
} }
} }
} }
@@ -429,7 +431,7 @@ impl<'a> Context<'a> {
None => { None => {
panic!("Ran out of {} registers when inserting copy before {}", panic!("Ran out of {} registers when inserting copy before {}",
rc, rc,
dfg.display_inst(inst)) dfg.display_inst(inst, self.isa))
} }
} }
} }