Add regspill and regfill instructions.

These are parallels to the existing regmove instruction, but the divert
the value to and from a stack slot.

Like regmove diversions, this is a temporary diversion that must be
local to the EBB.
This commit is contained in:
Jakob Stoklund Olesen
2017-10-04 12:42:53 -07:00
parent d4aeec6ece
commit dda3efcbdd
9 changed files with 123 additions and 3 deletions

View File

@@ -700,9 +700,12 @@ allocation pass and beyond.
.. autoinst:: fill .. autoinst:: fill
Register values can be temporarily diverted to other registers by the Register values can be temporarily diverted to other registers by the
:inst:`regmove` instruction. :inst:`regmove` instruction, and to and from stack slots by :inst:`regspill`
and :inst:`regfill`.
.. autoinst:: regmove .. autoinst:: regmove
.. autoinst:: regspill
.. autoinst:: regfill
Vector operations Vector operations
----------------- -----------------

View File

@@ -166,14 +166,21 @@ ebb0(v1: i32):
; Register diversions. ; Register diversions.
; This test file has no ISA, so we can unly use register unit numbers. ; This test file has no ISA, so we can unly use register unit numbers.
function %diversion(i32) { function %diversion(i32) {
ss0 = spill_slot 4
ebb0(v1: i32): ebb0(v1: i32):
regmove v1, %10 -> %20 regmove v1, %10 -> %20
regmove v1, %20 -> %10 regmove v1, %20 -> %10
regspill v1, %10 -> ss0
regfill v1, ss0 -> %10
return return
} }
; sameln: function %diversion(i32) native { ; sameln: function %diversion(i32) native {
; nextln: ebb0($v1: i32): ; nextln: $ss0 = spill_slot 4
; check: ebb0($v1: i32):
; nextln: regmove $v1, %10 -> %20 ; nextln: regmove $v1, %10 -> %20
; nextln: regmove $v1, %20 -> %10 ; nextln: regmove $v1, %20 -> %10
; nextln: regspill $v1, %10 -> $ss0
; nextln: regfill $v1, $ss0 -> %10
; nextln: return ; nextln: return
; nextln: } ; nextln: }

View File

@@ -58,6 +58,10 @@ StackStore = InstructionFormat(VALUE, stack_slot, offset32)
HeapAddr = InstructionFormat(heap, VALUE, uimm32) HeapAddr = InstructionFormat(heap, VALUE, uimm32)
RegMove = InstructionFormat(VALUE, ('src', regunit), ('dst', regunit)) RegMove = InstructionFormat(VALUE, ('src', regunit), ('dst', regunit))
RegSpill = InstructionFormat(
VALUE, ('src', regunit), ('dst', entities.stack_slot))
RegFill = InstructionFormat(
VALUE, ('src', entities.stack_slot), ('dst', regunit))
Trap = InstructionFormat(trapcode) Trap = InstructionFormat(trapcode)
CondTrap = InstructionFormat(VALUE, trapcode) CondTrap = InstructionFormat(VALUE, trapcode)

View File

@@ -514,6 +514,34 @@ regmove = Instruction(
ins=(x, src, dst), ins=(x, src, dst),
other_side_effects=True) other_side_effects=True)
regspill = Instruction(
'regspill', r"""
Temporarily divert ``x`` from ``src`` to ``SS``.
This instruction moves the location of a value from a register to a
stack slot without creating a new SSA value. It is used by the register
allocator to temporarily rearrange register assignments in order to
satisfy instruction constraints.
See also :inst:`regmove`.
""",
ins=(x, src, SS),
other_side_effects=True)
regfill = Instruction(
'regfill', r"""
Temporarily divert ``x`` from ``SS`` to ``dst``.
This instruction moves the location of a value from a stack slot to a
register without creating a new SSA value. It is used by the register
allocator to temporarily rearrange register assignments in order to
satisfy instruction constraints.
See also :inst:`regmove`.
""",
ins=(x, SS, dst),
other_side_effects=True)
# #
# Vector operations # Vector operations
# #

View File

@@ -32,7 +32,7 @@ def gen_recipe(recipe, fmt):
for o in recipe.outs) for o in recipe.outs)
# Regmove instructions get special treatment. # Regmove instructions get special treatment.
is_regmove = (recipe.format.name == 'RegMove') is_regmove = (recipe.format.name in ('RegMove', 'RegSpill', 'RegFill'))
# First unpack the instruction. # First unpack the instruction.
with fmt.indented( with fmt.indented(
@@ -111,6 +111,10 @@ def gen_recipe(recipe, fmt):
# diversion tracker. # diversion tracker.
if recipe.format.name == 'RegMove': if recipe.format.name == 'RegMove':
fmt.line('divert.regmove(arg, src, dst);') fmt.line('divert.regmove(arg, src, dst);')
elif recipe.format.name == 'RegSpill':
fmt.line('divert.regspill(arg, src, dst);')
elif recipe.format.name == 'RegFill':
fmt.line('divert.regfill(arg, src, dst);')
# Call hand-written code. If the recipe contains a code snippet, use # Call hand-written code. If the recipe contains a code snippet, use
# that. Otherwise cal a recipe function in the target ISA's binemit # that. Otherwise cal a recipe function in the target ISA's binemit

View File

@@ -213,6 +213,18 @@ pub enum InstructionData {
src: RegUnit, src: RegUnit,
dst: RegUnit, dst: RegUnit,
}, },
RegSpill {
opcode: Opcode,
arg: Value,
src: RegUnit,
dst: StackSlot,
},
RegFill {
opcode: Opcode,
arg: Value,
src: StackSlot,
dst: RegUnit,
},
Trap { opcode: Opcode, code: ir::TrapCode }, Trap { opcode: Opcode, code: ir::TrapCode },
CondTrap { CondTrap {
opcode: Opcode, opcode: Opcode,

View File

@@ -317,6 +317,12 @@ impl<'a> Verifier<'a> {
HeapAddr { heap, .. } => { HeapAddr { heap, .. } => {
self.verify_heap(inst, heap)?; self.verify_heap(inst, heap)?;
} }
RegSpill { dst, .. } => {
self.verify_stack_slot(inst, dst)?;
}
RegFill { src, .. } => {
self.verify_stack_slot(inst, src)?;
}
// Exhaustive list so we can't forget to add new formats // Exhaustive list so we can't forget to add new formats
Unary { .. } | Unary { .. } |

View File

@@ -385,6 +385,22 @@ pub fn write_operands(
write!(w, " {}, %{} -> %{}", arg, src, dst) write!(w, " {}, %{} -> %{}", arg, src, dst)
} }
} }
RegSpill { arg, src, dst, .. } => {
if let Some(isa) = isa {
let regs = isa.register_info();
write!(w, " {}, {} -> {}", arg, regs.display_regunit(src), dst)
} else {
write!(w, " {}, %{} -> {}", arg, src, dst)
}
}
RegFill { arg, src, dst, .. } => {
if let Some(isa) = isa {
let regs = isa.register_info();
write!(w, " {}, {} -> {}", arg, src, regs.display_regunit(dst))
} else {
write!(w, " {}, {} -> %{}", arg, src, dst)
}
}
Trap { code, .. } => write!(w, " {}", code), Trap { code, .. } => write!(w, " {}", code),
CondTrap { arg, code, .. } => write!(w, " {}, {}", arg, code), CondTrap { arg, code, .. } => write!(w, " {}, {}", arg, code),
} }

View File

@@ -2223,6 +2223,46 @@ impl<'a> Parser<'a> {
dst, dst,
} }
} }
InstructionFormat::RegSpill => {
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 '->' before destination stack slot",
)?;
let dst = self.match_ss("expected stack slot number: ss«n»")
.and_then(|num| ctx.get_ss(num, &self.loc))?;
InstructionData::RegSpill {
opcode,
arg,
src,
dst,
}
}
InstructionFormat::RegFill => {
let arg = self.match_value("expected SSA value operand")?;
self.match_token(
Token::Comma,
"expected ',' between operands",
)?;
let src = self.match_ss("expected stack slot number: ss«n»")
.and_then(|num| ctx.get_ss(num, &self.loc))?;
self.match_token(
Token::Arrow,
"expected '->' before destination register units",
)?;
let dst = self.match_regunit(ctx.unique_isa)?;
InstructionData::RegFill {
opcode,
arg,
src,
dst,
}
}
InstructionFormat::Trap => { InstructionFormat::Trap => {
let code = self.match_enum("expected trap code")?; let code = self.match_enum("expected trap code")?;
InstructionData::Trap { opcode, code } InstructionData::Trap { opcode, code }