Add an ISA argument to dfg.display_inst().
Include ISA-specific annotations in tracing and error messages.
This commit is contained in:
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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'),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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!();
|
||||||
|
|||||||
@@ -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), &[]);
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user