Give better error messages in "test binemit".
When an instruction can't be encoded, provide a bit more help:
Detect missing register assignments for input and output operands.
List encodings that where considered and rejected.
@@ -7,6 +7,7 @@ use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt::Write;
use cretonne::binemit;
+use cretonne::dbg::DisplayList;
use cretonne::ir;
use cretonne::ir::entities::AnyEntity;
use cretonne::regalloc::RegDiversions;
@@ -137,26 +138,27 @@ impl SubTest for TestBinEmit {
divert.clear();
for inst in func.layout.ebb_insts(ebb) {
if !func.encodings[inst].is_legal() {
+ // Find an encoding that satisfies both immediate field and register
+ // constraints.
+ if let Some(enc) = {
let mut legal_encodings = isa.legal_encodings(
&func.dfg,
&func.dfg[inst],
func.dfg.ctrl_typevar(inst),
- );
-
- let enc = if is_compressed {
- // Get the smallest legal encoding
- legal_encodings
- .filter(|e| {
+ ).filter(|e| {
let recipe_constraints = &encinfo.constraints[e.recipe()];
recipe_constraints.satisfied(inst, &divert, &func)
- })
- .min_by_key(|&e| encinfo.bytes(e))
+ });
+
+ if is_compressed {
+ // Get the smallest legal encoding
+ legal_encodings.min_by_key(|&e| encinfo.bytes(e))
} else {
// If not using compressed, just use the first encoding.
legal_encodings.next()
- };
-
- if let Some(enc) = enc {
+ }
+ }
+ {
func.encodings[inst] = enc;
}
}
@@ -215,6 +217,17 @@ impl SubTest for TestBinEmit {
// Send legal encodings into the emitter.
if enc.is_legal() {
+ // Generate a better error message if output locations are not specified.
+ if let Some(&v) = func.dfg.inst_results(inst).iter().find(|&&v| {
+ !func.locations[v].is_assigned()
+ })
+ {
+ return Err(format!(
+ "Missing register/stack slot for {} in {}",
+ v,
+ func.dfg.display_inst(inst, isa)
+ ));
+ }
let before = sink.offset;
isa.emit_inst(&func, inst, &mut divert, &mut sink);
let emitted = sink.offset - before;
@@ -231,12 +244,40 @@ impl SubTest for TestBinEmit {
// Check against bin: directives.
if let Some(want) = bins.remove(&inst) {
if !enc.is_legal() {
+ // A possible cause of an unencoded instruction is a missing location for
+ // one of the input operands.
+ if let Some(&v) = func.dfg.inst_args(inst).iter().find(|&&v| {
+ !func.locations[v].is_assigned()
+ })
+ {
return Err(format!(
- "{} can't be encoded: {}",
- inst,
+ "Missing register/stack slot for {} in {}",
+ v,
func.dfg.display_inst(inst, isa)
));
}
+
+ // Do any encodings exist?
+ let encodings = isa.legal_encodings(
+ &func.dfg,
+ &func.dfg[inst],
+ func.dfg.ctrl_typevar(inst),
+ ).map(|e| encinfo.display(e))
+ .collect::<Vec<_>>();
+
+ if encodings.is_empty() {
+ return Err(format!(
+ "No encodings found for: {}",
+ func.dfg.display_inst(inst, isa)
+ ));
+ } else {
+ return Err(format!(
+ "No matching encodings for {} in {}",
+ func.dfg.display_inst(inst, isa),
+ DisplayList(&encodings),
+ ));
+ }
+ }
let have = sink.text.trim();
if have != want {
return Err(format!(
