Add a regmove instruction.
This will be used to locally change the register locations of values in order to satisfy instruction constraints.
This commit is contained in:
@@ -583,6 +583,11 @@ allocation pass and beyond.
|
||||
.. autoinst:: spill
|
||||
.. autoinst:: fill
|
||||
|
||||
Register values can be temporarily diverted to other registers by the
|
||||
:inst:`regmove` instruction.
|
||||
|
||||
.. autoinst:: regmove
|
||||
|
||||
Vector operations
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -155,3 +155,18 @@ ebb0(v1: i32):
|
||||
; nextln: store $v2, $v1
|
||||
; nextln: store aligned $v3, $v1+12
|
||||
; nextln: store notrap aligned $v3, $v1-12
|
||||
|
||||
; Register diversions.
|
||||
; This test file has no ISA, so we can unly use register unit numbers.
|
||||
function diversion(i32) {
|
||||
ebb0(v1: i32):
|
||||
regmove v1, %10 -> %20
|
||||
regmove v1, %20 -> %10
|
||||
return
|
||||
}
|
||||
; sameln: function diversion(i32) {
|
||||
; nextln: ebb0($v1: i32):
|
||||
; nextln: regmove $v1, %10 -> %20
|
||||
; nextln: regmove $v1, %20 -> %10
|
||||
; nextln: return
|
||||
; nextln: }
|
||||
|
||||
@@ -9,7 +9,7 @@ from __future__ import absolute_import
|
||||
from cdsl.formats import InstructionFormat
|
||||
from cdsl.operands import VALUE, VARIABLE_ARGS
|
||||
from .immediates import imm64, uimm8, ieee32, ieee64, offset32, uoffset32
|
||||
from .immediates import intcc, floatcc, memflags
|
||||
from .immediates import intcc, floatcc, memflags, regunit
|
||||
from .entities import ebb, sig_ref, func_ref, jump_table, stack_slot
|
||||
|
||||
Nullary = InstructionFormat()
|
||||
@@ -57,5 +57,7 @@ StackStore = InstructionFormat(VALUE, stack_slot, offset32)
|
||||
HeapLoad = InstructionFormat(VALUE, uoffset32)
|
||||
HeapStore = InstructionFormat(VALUE, VALUE, uoffset32)
|
||||
|
||||
RegMove = InstructionFormat(VALUE, ('src', regunit), ('dst', regunit))
|
||||
|
||||
# Finally extract the names of global variables in this module.
|
||||
InstructionFormat.extract_names(globals())
|
||||
|
||||
@@ -96,3 +96,9 @@ memflags = ImmediateKind(
|
||||
'memflags',
|
||||
'Memory operation flags',
|
||||
default_member='flags', rust_type='MemFlags')
|
||||
|
||||
#: A register unit in the current target ISA.
|
||||
regunit = ImmediateKind(
|
||||
'regunit',
|
||||
'A register unit in the target ISA',
|
||||
rust_type='RegUnit')
|
||||
|
||||
@@ -10,7 +10,7 @@ from cdsl.typevar import TypeVar
|
||||
from cdsl.instructions import Instruction, InstructionGroup
|
||||
from base.types import i8, f32, f64, b1
|
||||
from base.immediates import imm64, uimm8, ieee32, ieee64, offset32, uoffset32
|
||||
from base.immediates import intcc, floatcc, memflags
|
||||
from base.immediates import intcc, floatcc, memflags, regunit
|
||||
from base import entities
|
||||
import base.formats # noqa
|
||||
|
||||
@@ -467,6 +467,23 @@ fill = Instruction(
|
||||
""",
|
||||
ins=x, outs=a)
|
||||
|
||||
src = Operand('src', regunit)
|
||||
dst = Operand('dst', regunit)
|
||||
|
||||
regmove = Instruction(
|
||||
'regmove', r"""
|
||||
Temporarily divert ``x`` from ``src`` to ``dst``.
|
||||
|
||||
This instruction moves the location of a value from one register to
|
||||
another without creating a new SSA value. It is used by the register
|
||||
allocator to temporarily rearrange register assignments in order to
|
||||
satisfy instruction constraints.
|
||||
|
||||
The register diversions created by this instruction must be undone
|
||||
before the value leaves the EBB. At the entry to a new EBB, all live
|
||||
values must be in their originally assigned registers.
|
||||
""",
|
||||
ins=(x, src, dst))
|
||||
|
||||
#
|
||||
# Vector operations
|
||||
|
||||
@@ -9,6 +9,7 @@ use ir::{Opcode, Type, Inst, Value, Ebb, JumpTable, SigRef, FuncRef, StackSlot,
|
||||
MemFlags};
|
||||
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, Offset32, Uoffset32};
|
||||
use ir::condcodes::{IntCC, FloatCC};
|
||||
use isa::RegUnit;
|
||||
|
||||
/// Base trait for instruction builders.
|
||||
///
|
||||
|
||||
@@ -687,7 +687,7 @@ impl<'a> fmt::Display for DisplayInst<'a> {
|
||||
} else {
|
||||
write!(f, "{}.{}", inst.opcode(), typevar)?;
|
||||
}
|
||||
write_operands(f, dfg, self.1)
|
||||
write_operands(f, dfg, None, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ use ir::{Value, Type, Ebb, JumpTable, SigRef, FuncRef, StackSlot, MemFlags};
|
||||
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, Offset32, Uoffset32};
|
||||
use ir::condcodes::*;
|
||||
use ir::types;
|
||||
use isa::RegUnit;
|
||||
|
||||
use entity_list;
|
||||
use ref_slice::{ref_slice, ref_slice_mut};
|
||||
@@ -203,6 +204,12 @@ pub enum InstructionData {
|
||||
args: [Value; 2],
|
||||
offset: Offset32,
|
||||
},
|
||||
RegMove {
|
||||
opcode: Opcode,
|
||||
arg: Value,
|
||||
src: RegUnit,
|
||||
dst: RegUnit,
|
||||
},
|
||||
}
|
||||
|
||||
/// A variable list of `Value` operands used for function call arguments and passing arguments to
|
||||
|
||||
@@ -284,7 +284,8 @@ impl<'a> Verifier<'a> {
|
||||
&HeapLoad { .. } |
|
||||
&HeapStore { .. } |
|
||||
&Load { .. } |
|
||||
&Store { .. } => {}
|
||||
&Store { .. } |
|
||||
&RegMove { .. } => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -225,12 +225,16 @@ fn write_instruction(w: &mut Write,
|
||||
None => write!(w, "{}", opcode)?,
|
||||
}
|
||||
|
||||
write_operands(w, &func.dfg, inst)?;
|
||||
write_operands(w, &func.dfg, isa, inst)?;
|
||||
writeln!(w, "")
|
||||
}
|
||||
|
||||
/// Write the operands of `inst` to `w` with a prepended space.
|
||||
pub fn write_operands(w: &mut Write, dfg: &DataFlowGraph, inst: Inst) -> Result {
|
||||
pub fn write_operands(w: &mut Write,
|
||||
dfg: &DataFlowGraph,
|
||||
isa: Option<&TargetIsa>,
|
||||
inst: Inst)
|
||||
-> Result {
|
||||
let pool = &dfg.value_lists;
|
||||
use ir::instructions::InstructionData::*;
|
||||
match dfg[inst] {
|
||||
@@ -321,6 +325,19 @@ pub fn write_operands(w: &mut Write, dfg: &DataFlowGraph, inst: Inst) -> Result
|
||||
offset,
|
||||
..
|
||||
} => write!(w, "{} {}, {}{}", flags, args[0], args[1], offset),
|
||||
RegMove { arg, src, dst, .. } => {
|
||||
if let Some(isa) = isa {
|
||||
let regs = isa.register_info();
|
||||
write!(w,
|
||||
" {}, {} -> {}",
|
||||
arg,
|
||||
regs.display_regunit(src),
|
||||
regs.display_regunit(dst))
|
||||
} else {
|
||||
write!(w, " {}, %{} -> %{}", arg, src, dst)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ use cretonne::ir::types::VOID;
|
||||
use cretonne::ir::immediates::{Imm64, Offset32, Uoffset32, Ieee32, Ieee64};
|
||||
use cretonne::ir::entities::AnyEntity;
|
||||
use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs};
|
||||
use cretonne::isa::{self, TargetIsa, Encoding};
|
||||
use cretonne::isa::{self, TargetIsa, Encoding, RegUnit};
|
||||
use cretonne::settings::{self, Configurable};
|
||||
use testfile::{TestFile, Details, Comment};
|
||||
use error::{Location, Error, Result};
|
||||
@@ -551,6 +551,29 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Match and consume a register unit either by number `%15` or by name `%rax`.
|
||||
fn match_regunit(&mut self, isa: Option<&TargetIsa>) -> Result<RegUnit> {
|
||||
if let Some(Token::Name(name)) = self.token() {
|
||||
self.consume();
|
||||
match isa {
|
||||
Some(isa) => {
|
||||
isa.register_info()
|
||||
.parse_regunit(name)
|
||||
.ok_or_else(|| self.error("invalid register name"))
|
||||
}
|
||||
None => {
|
||||
name.parse()
|
||||
.map_err(|_| self.error("invalid register number"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match isa {
|
||||
Some(isa) => err!(self.loc, "Expected {} register unit", isa.name()),
|
||||
None => err!(self.loc, "Expected register unit number"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a list of test commands.
|
||||
pub fn parse_test_commands(&mut self) -> Vec<TestCommand<'a>> {
|
||||
let mut list = Vec::new();
|
||||
@@ -1664,6 +1687,19 @@ impl<'a> Parser<'a> {
|
||||
offset,
|
||||
}
|
||||
}
|
||||
InstructionFormat::RegMove => {
|
||||
let arg = self.match_value("expected SSA value operand")?;
|
||||
self.match_token(Token::Comma, "expected ',' between operands")?;
|
||||
let src = self.match_regunit(ctx.unique_isa)?;
|
||||
self.match_token(Token::Arrow, "expected '->' between register units")?;
|
||||
let dst = self.match_regunit(ctx.unique_isa)?;
|
||||
InstructionData::RegMove {
|
||||
opcode,
|
||||
arg,
|
||||
src,
|
||||
dst,
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(idata)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user