Add RISC-V encodings for spill and fill.

Add a Stack() class for specifying operand constraints for values on the
stack.

Add encoding recipes for RISC-V spill and fill instructions. Don't
implement the encoding recipe functions yet since we don't have the
stack slot layout yet.
This commit is contained in:
Jakob Stoklund Olesen
2017-06-13 13:39:52 -07:00
parent ea8a8a95a8
commit 5336bbd4cc
6 changed files with 53 additions and 6 deletions

View File

@@ -1,7 +1,7 @@
"""Defining instruction set architectures.""" """Defining instruction set architectures."""
from __future__ import absolute_import from __future__ import absolute_import
from .predicates import And from .predicates import And
from .registers import RegClass, Register from .registers import RegClass, Register, Stack
from .ast import Apply from .ast import Apply
# The typing module is only required by mypy, and we don't use these imports # The typing module is only required by mypy, and we don't use these imports
@@ -14,7 +14,7 @@ try:
from .settings import SettingGroup # noqa from .settings import SettingGroup # noqa
from .types import ValueType # noqa from .types import ValueType # noqa
from .registers import RegBank # noqa from .registers import RegBank # noqa
OperandConstraint = Union[RegClass, Register, int] OperandConstraint = Union[RegClass, Register, int, Stack]
ConstraintSeq = Union[OperandConstraint, Tuple[OperandConstraint, ...]] ConstraintSeq = Union[OperandConstraint, Tuple[OperandConstraint, ...]]
# Instruction specification for encodings. Allows for predicated # Instruction specification for encodings. Allows for predicated
# instructions. # instructions.
@@ -187,6 +187,7 @@ class EncRecipe(object):
- A `Register` specifying a fixed-register operand. - A `Register` specifying a fixed-register operand.
- An integer indicating that this result is tied to a value operand, so - An integer indicating that this result is tied to a value operand, so
they must use the same register. they must use the same register.
- A `Stack` specifying a value in a stack slot.
The `branch_range` argument must be provided for recipes that can encode The `branch_range` argument must be provided for recipes that can encode
branch instructions. It is an `(origin, bits)` tuple describing the exact branch instructions. It is an `(origin, bits)` tuple describing the exact
@@ -245,7 +246,9 @@ class EncRecipe(object):
# Check that it is in range. # Check that it is in range.
assert c >= 0 and c < len(self.ins) assert c >= 0 and c < len(self.ins)
else: else:
assert isinstance(c, RegClass) or isinstance(c, Register) assert (isinstance(c, RegClass)
or isinstance(c, Register)
or isinstance(c, Stack))
return seq return seq
def ties(self): def ties(self):

View File

@@ -340,3 +340,15 @@ class Register(object):
# type: (RegClass, int) -> None # type: (RegClass, int) -> None
self.regclass = rc self.regclass = rc
self.unit = unit self.unit = unit
class Stack(object):
"""
An operand that must be in a stack slot.
A `Stack` object can be used to indicate an operand constraint for a value
operand that must live in a stack slot.
"""
def __init__(self, rc):
# type: (RegClass) -> None
self.regclass = rc

View File

@@ -56,7 +56,7 @@ from unique_table import UniqueSeqTable
from collections import OrderedDict, defaultdict from collections import OrderedDict, defaultdict
import math import math
import itertools import itertools
from cdsl.registers import RegClass, Register from cdsl.registers import RegClass, Register, Stack
from cdsl.predicates import FieldPredicate from cdsl.predicates import FieldPredicate
try: try:
@@ -519,6 +519,10 @@ def emit_operand_constraints(
assert cons == tied[n], "Invalid tied constraint" assert cons == tied[n], "Invalid tied constraint"
fmt.format('kind: ConstraintKind::Tied({}),', cons) fmt.format('kind: ConstraintKind::Tied({}),', cons)
fmt.format('regclass: {},', recipe.ins[cons]) fmt.format('regclass: {},', recipe.ins[cons])
elif isinstance(cons, Stack):
assert n not in tied, "Can't tie stack operand"
fmt.line('kind: ConstraintKind::Stack,')
fmt.format('regclass: {},', cons.regclass)
else: else:
raise AssertionError( raise AssertionError(
'Unsupported constraint {}'.format(cons)) 'Unsupported constraint {}'.format(cons))

View File

@@ -6,8 +6,9 @@ from base import instructions as base
from base.immediates import intcc from base.immediates import intcc
from .defs import RV32, RV64 from .defs import RV32, RV64
from .recipes import OPIMM, OPIMM32, OP, OP32, LUI, BRANCH, JALR, JAL from .recipes import OPIMM, OPIMM32, OP, OP32, LUI, BRANCH, JALR, JAL
from .recipes import LOAD, STORE
from .recipes import R, Rshamt, Ricmp, I, Iicmp, Iret from .recipes import R, Rshamt, Ricmp, I, Iicmp, Iret
from .recipes import U, UJ, UJcall, SB, SBzero from .recipes import U, UJ, UJcall, SB, SBzero, GPsp, GPfi
from .settings import use_m from .settings import use_m
from cdsl.ast import Var from cdsl.ast import Var
@@ -114,3 +115,11 @@ for inst, f3 in [
# is added by legalize_signature(). # is added by legalize_signature().
RV32.enc(base.x_return, Iret, JALR()) RV32.enc(base.x_return, Iret, JALR())
RV64.enc(base.x_return, Iret, JALR()) RV64.enc(base.x_return, Iret, JALR())
# Spill and fill.
RV32.enc(base.spill.i32, GPsp, STORE(0b010))
RV64.enc(base.spill.i32, GPsp, STORE(0b010))
RV64.enc(base.spill.i64, GPsp, STORE(0b011))
RV32.enc(base.fill.i32, GPfi, LOAD(0b010))
RV64.enc(base.fill.i32, GPfi, LOAD(0b010))
RV64.enc(base.fill.i64, GPfi, LOAD(0b011))

View File

@@ -11,8 +11,9 @@ instruction formats described in the reference:
from __future__ import absolute_import from __future__ import absolute_import
from cdsl.isa import EncRecipe from cdsl.isa import EncRecipe
from cdsl.predicates import IsSignedInt from cdsl.predicates import IsSignedInt
from cdsl.registers import Stack
from base.formats import Binary, BinaryImm, MultiAry, IntCompare, IntCompareImm from base.formats import Binary, BinaryImm, MultiAry, IntCompare, IntCompareImm
from base.formats import UnaryImm, BranchIcmp, Branch, Jump, Call from base.formats import Unary, UnaryImm, BranchIcmp, Branch, Jump, Call
from .registers import GPR from .registers import GPR
# The low 7 bits of a RISC-V instruction is the base opcode. All 32-bit # The low 7 bits of a RISC-V instruction is the base opcode. All 32-bit
@@ -134,3 +135,13 @@ SBzero = EncRecipe(
'SBzero', Branch, size=4, 'SBzero', Branch, size=4,
ins=(GPR), outs=(), ins=(GPR), outs=(),
branch_range=(0, 13)) branch_range=(0, 13))
# Spill of a GPR.
GPsp = EncRecipe(
'GPsp', Unary, size=4,
ins=GPR, outs=Stack(GPR))
# Fill of a GPR.
GPfi = EncRecipe(
'GPfi', Unary, size=4,
ins=Stack(GPR), outs=GPR)

View File

@@ -333,3 +333,11 @@ fn recipe_ujcall<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut
panic!("Expected Call format: {:?}", func.dfg[inst]); panic!("Expected Call format: {:?}", func.dfg[inst]);
} }
} }
fn recipe_gpsp<CS: CodeSink + ?Sized>(_func: &Function, _inst: Inst, _sink: &mut CS) {
unimplemented!();
}
fn recipe_gpfi<CS: CodeSink + ?Sized>(_func: &Function, _inst: Inst, _sink: &mut CS) {
unimplemented!();
}