From dda3efcbdd18e2588878db420adcf40f7083db92 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 4 Oct 2017 12:42:53 -0700 Subject: [PATCH] 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. --- cranelift/docs/langref.rst | 5 +++- cranelift/filetests/parser/tiny.cton | 9 +++++- lib/cretonne/meta/base/formats.py | 4 +++ lib/cretonne/meta/base/instructions.py | 28 ++++++++++++++++++ lib/cretonne/meta/gen_binemit.py | 6 +++- lib/cretonne/src/ir/instructions.rs | 12 ++++++++ lib/cretonne/src/verifier/mod.rs | 6 ++++ lib/cretonne/src/write.rs | 16 +++++++++++ lib/reader/src/parser.rs | 40 ++++++++++++++++++++++++++ 9 files changed, 123 insertions(+), 3 deletions(-) diff --git a/cranelift/docs/langref.rst b/cranelift/docs/langref.rst index 1e148190e6..5d2b46cc73 100644 --- a/cranelift/docs/langref.rst +++ b/cranelift/docs/langref.rst @@ -700,9 +700,12 @@ allocation pass and beyond. .. autoinst:: fill 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:: regspill +.. autoinst:: regfill Vector operations ----------------- diff --git a/cranelift/filetests/parser/tiny.cton b/cranelift/filetests/parser/tiny.cton index e538b5acaa..9727e40177 100644 --- a/cranelift/filetests/parser/tiny.cton +++ b/cranelift/filetests/parser/tiny.cton @@ -166,14 +166,21 @@ ebb0(v1: i32): ; Register diversions. ; This test file has no ISA, so we can unly use register unit numbers. function %diversion(i32) { + ss0 = spill_slot 4 + ebb0(v1: i32): regmove v1, %10 -> %20 regmove v1, %20 -> %10 + regspill v1, %10 -> ss0 + regfill v1, ss0 -> %10 return } ; 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, %20 -> %10 +; nextln: regspill $v1, %10 -> $ss0 +; nextln: regfill $v1, $ss0 -> %10 ; nextln: return ; nextln: } diff --git a/lib/cretonne/meta/base/formats.py b/lib/cretonne/meta/base/formats.py index 7fd93de1f9..0f31ff2c5f 100644 --- a/lib/cretonne/meta/base/formats.py +++ b/lib/cretonne/meta/base/formats.py @@ -58,6 +58,10 @@ StackStore = InstructionFormat(VALUE, stack_slot, offset32) HeapAddr = InstructionFormat(heap, VALUE, uimm32) 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) CondTrap = InstructionFormat(VALUE, trapcode) diff --git a/lib/cretonne/meta/base/instructions.py b/lib/cretonne/meta/base/instructions.py index f49a532a3f..6e94b4c553 100644 --- a/lib/cretonne/meta/base/instructions.py +++ b/lib/cretonne/meta/base/instructions.py @@ -514,6 +514,34 @@ regmove = Instruction( ins=(x, src, dst), 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 # diff --git a/lib/cretonne/meta/gen_binemit.py b/lib/cretonne/meta/gen_binemit.py index 58a44473a3..9e2bac451f 100644 --- a/lib/cretonne/meta/gen_binemit.py +++ b/lib/cretonne/meta/gen_binemit.py @@ -32,7 +32,7 @@ def gen_recipe(recipe, fmt): for o in recipe.outs) # Regmove instructions get special treatment. - is_regmove = (recipe.format.name == 'RegMove') + is_regmove = (recipe.format.name in ('RegMove', 'RegSpill', 'RegFill')) # First unpack the instruction. with fmt.indented( @@ -111,6 +111,10 @@ def gen_recipe(recipe, fmt): # diversion tracker. if recipe.format.name == 'RegMove': 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 # that. Otherwise cal a recipe function in the target ISA's binemit diff --git a/lib/cretonne/src/ir/instructions.rs b/lib/cretonne/src/ir/instructions.rs index 14bd3de726..2174bb4c99 100644 --- a/lib/cretonne/src/ir/instructions.rs +++ b/lib/cretonne/src/ir/instructions.rs @@ -213,6 +213,18 @@ pub enum InstructionData { src: 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 }, CondTrap { opcode: Opcode, diff --git a/lib/cretonne/src/verifier/mod.rs b/lib/cretonne/src/verifier/mod.rs index d76a5efbba..735f78a754 100644 --- a/lib/cretonne/src/verifier/mod.rs +++ b/lib/cretonne/src/verifier/mod.rs @@ -317,6 +317,12 @@ impl<'a> Verifier<'a> { HeapAddr { 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 Unary { .. } | diff --git a/lib/cretonne/src/write.rs b/lib/cretonne/src/write.rs index d2f903cc7a..a1e195cd17 100644 --- a/lib/cretonne/src/write.rs +++ b/lib/cretonne/src/write.rs @@ -385,6 +385,22 @@ pub fn write_operands( 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), CondTrap { arg, code, .. } => write!(w, " {}, {}", arg, code), } diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index e334319e91..354cb02a22 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -2223,6 +2223,46 @@ impl<'a> Parser<'a> { 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 => { let code = self.match_enum("expected trap code")?; InstructionData::Trap { opcode, code }