From 826d4062fb9044d2f2a82c7ac56a2a2531ec3a0d Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 4 Oct 2017 16:33:50 -0700 Subject: [PATCH] Apply register diversions during binemit tests. When "binemit" tests encode instructions, keep track of the current set of register diversions, and use the diverted locations to check operand constraints. This matches how constraints are applied during a real binemit phase. --- cranelift/src/filetest/binemit.rs | 6 ++++-- lib/cretonne/src/isa/constraints.rs | 7 ++++--- lib/cretonne/src/regalloc/diversion.rs | 29 ++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/cranelift/src/filetest/binemit.rs b/cranelift/src/filetest/binemit.rs index f1a493c749..da0e2012a0 100644 --- a/cranelift/src/filetest/binemit.rs +++ b/cranelift/src/filetest/binemit.rs @@ -114,6 +114,7 @@ impl SubTest for TestBinEmit { let is_compressed = isa.flags().is_compressed(); // Give an encoding to any instruction that doesn't already have one. + let mut divert = RegDiversions::new(); for ebb in func.layout.ebbs() { for inst in func.layout.ebb_insts(ebb) { if !func.encodings[inst].is_legal() { @@ -128,7 +129,7 @@ impl SubTest for TestBinEmit { legal_encodings .filter(|e| { let recipe_constraints = &encinfo.constraints[e.recipe()]; - recipe_constraints.satisfied(inst, &func) + recipe_constraints.satisfied(inst, &divert, &func) }) .min_by_key(|&e| encinfo.bytes(e)) } else { @@ -140,6 +141,7 @@ impl SubTest for TestBinEmit { func.encodings[inst] = enc; } } + divert.apply(&func.dfg[inst]); } } @@ -178,8 +180,8 @@ impl SubTest for TestBinEmit { } // Now emit all instructions. + divert.clear(); let mut sink = TextSink::new(isa); - let mut divert = RegDiversions::new(); for ebb in func.layout.ebbs() { divert.clear(); // Correct header offsets should have been computed by `relax_branches()`. diff --git a/lib/cretonne/src/isa/constraints.rs b/lib/cretonne/src/isa/constraints.rs index d9fc3aa8ea..9efcf7bb4f 100644 --- a/lib/cretonne/src/isa/constraints.rs +++ b/lib/cretonne/src/isa/constraints.rs @@ -10,6 +10,7 @@ use binemit::CodeOffset; use isa::{RegClass, RegUnit}; use ir::{Function, ValueLoc, Inst}; +use regalloc::RegDiversions; /// Register constraint for a single value operand or instruction result. pub struct OperandConstraint { @@ -109,9 +110,9 @@ pub struct RecipeConstraints { impl RecipeConstraints { /// Check that these constraints are satisfied by the operands on `inst`. - pub fn satisfied(&self, inst: Inst, func: &Function) -> bool { + pub fn satisfied(&self, inst: Inst, divert: &RegDiversions, func: &Function) -> bool { for (&arg, constraint) in func.dfg.inst_args(inst).iter().zip(self.ins) { - let loc = func.locations[arg]; + let loc = divert.get(arg, &func.locations); if let ConstraintKind::Tied(out_index) = constraint.kind { let out_val = func.dfg.inst_results(inst)[out_index as usize]; @@ -127,7 +128,7 @@ impl RecipeConstraints { } for (&arg, constraint) in func.dfg.inst_results(inst).iter().zip(self.outs) { - let loc = func.locations[arg]; + let loc = divert.get(arg, &func.locations); if !constraint.satisfied(loc) { return false; } diff --git a/lib/cretonne/src/regalloc/diversion.rs b/lib/cretonne/src/regalloc/diversion.rs index 9d241ebcdd..c6d25f543e 100644 --- a/lib/cretonne/src/regalloc/diversion.rs +++ b/lib/cretonne/src/regalloc/diversion.rs @@ -8,6 +8,7 @@ //! EBB. use ir::{Value, ValueLoc, ValueLocations, StackSlot}; +use ir::{InstructionData, Opcode}; use isa::{RegUnit, RegInfo}; use std::fmt; @@ -118,6 +119,34 @@ impl RegDiversions { self.divert(value, ValueLoc::Stack(from), ValueLoc::Reg(to)); } + /// Apply the effect of `inst`. + /// + /// If `inst` is a `regmove`, `regfill`, or `regspill` instruction, update the diversions to + /// match. + pub fn apply(&mut self, inst: &InstructionData) { + match *inst { + InstructionData::RegMove { + opcode: Opcode::Regmove, + arg, + src, + dst, + } => self.regmove(arg, src, dst), + InstructionData::RegSpill { + opcode: Opcode::Regspill, + arg, + src, + dst, + } => self.regspill(arg, src, dst), + InstructionData::RegFill { + opcode: Opcode::Regfill, + arg, + src, + dst, + } => self.regfill(arg, src, dst), + _ => {} + } + } + /// Drop any recorded move for `value`. /// /// Returns the `to` location of the removed diversion.