Add RISC-V arithmetic w/immediate operand encodings.

Add new instruction predicates to support the 'I' encoding recipe: IsSignedInt,
IsUnsignedInt used to test that an immediate operand is in the allowed range.
This commit is contained in:
Jakob Stoklund Olesen
2016-08-23 14:45:24 -07:00
parent 5a5688e446
commit 1da15a10d7
4 changed files with 106 additions and 9 deletions

View File

@@ -725,6 +725,12 @@ class FormatField(object):
def __str__(self): def __str__(self):
return '{}.{}'.format(self.format.name, self.name) return '{}.{}'.format(self.format.name, self.name)
def rust_name(self):
if self.format.boxed_storage:
return 'data.' + self.name
else:
return self.name
class Instruction(object): class Instruction(object):
""" """
@@ -983,9 +989,13 @@ class EncRecipe(object):
:py:class:`InstructionFormat`. :py:class:`InstructionFormat`.
""" """
def __init__(self, name, format): def __init__(self, name, format, instp=None, isap=None):
self.name = name self.name = name
self.format = format self.format = format
self.instp = instp
self.isap = isap
if instp:
assert instp.predicate_context() == format
class Encoding(object): class Encoding(object):

View File

@@ -125,3 +125,79 @@ class Not(Predicate):
def rust_predicate(self, prec): def rust_predicate(self, prec):
return '!' + self.parts[0].rust_predicate(Not.precedence) return '!' + self.parts[0].rust_predicate(Not.precedence)
class FieldPredicate(object):
"""
An instruction predicate that performs a test on a single `FormatField`.
:param field: The `FormatField` to be tested.
:param method: Boolean predicate method to call.
:param args: Arguments for the predicate method.
"""
def __init__(self, field, method, args):
self.field = field
self.method = method
self.args = args
def predicate_context(self):
"""
This predicate can be evaluated in the context of an instruction
format.
"""
return self.field.format
def rust_predicate(self, prec):
"""
Return a string of Rust code that evaluates this predicate.
"""
return '{}.{}({})'.format(
self.field.rust_name(),
self.method,
', '.join(self.args))
class IsSignedInt(FieldPredicate):
"""
Instruction predicate that checks if an immediate instruction format field
is representable as an n-bit two's complement integer.
:param field: `FormatField` to be checked.
:param width: Number of bits in the allowed range.
:param scale: Number of low bits that must be 0.
The predicate is true if the field is in the range:
`-2^(width-1) -- 2^(width-1)-1`
and a multiple of `2^scale`.
"""
def __init__(self, field, width, scale=0):
super(IsSignedInt, self).__init__(
field, 'is_signed_int', (width, scale))
self.width = width
self.scale = scale
assert width >= 0 and width <= 64
assert scale >= 0 and scale < width
class IsUnsignedInt(FieldPredicate):
"""
Instruction predicate that checks if an immediate instruction format field
is representable as an n-bit unsigned complement integer.
:param field: `FormatField` to be checked.
:param width: Number of bits in the allowed range.
:param scale: Number of low bits that must be 0.
The predicate is true if the field is in the range:
`0 -- 2^width - 1` and a multiple of `2^scale`.
"""
def __init__(self, field, width, scale=0):
super(IsUnsignedInt, self).__init__(
field, 'is_unsigned_int', (width, scale))
self.width = width
self.scale = scale
assert width >= 0 and width <= 64
assert scale >= 0 and scale < width

View File

@@ -4,20 +4,28 @@ RISC-V Encodings.
from __future__ import absolute_import from __future__ import absolute_import
from cretonne import base from cretonne import base
from .defs import RV32, RV64 from .defs import RV32, RV64
from .recipes import OPIMM, OPIMM32, OP, OP32, R, Rshamt from .recipes import OPIMM, OPIMM32, OP, OP32, R, Rshamt, I
# Basic arithmetic binary instructions are encoded in an R-type instruction. # Basic arithmetic binary instructions are encoded in an R-type instruction.
for inst, f3, f7 in [ for inst, inst_imm, f3, f7 in [
(base.iadd, 0b000, 0b0000000), (base.iadd, base.iadd_imm, 0b000, 0b0000000),
(base.isub, 0b000, 0b0100000), (base.isub, None, 0b000, 0b0100000),
(base.bxor, 0b100, 0b0000000), (base.bxor, base.bxor_imm, 0b100, 0b0000000),
(base.bor, 0b110, 0b0000000), (base.bor, base.bor_imm, 0b110, 0b0000000),
(base.band, 0b111, 0b0000000) (base.band, base.band_imm, 0b111, 0b0000000)
]: ]:
RV32.enc(inst.i32, R, OP(f3, f7)) RV32.enc(inst.i32, R, OP(f3, f7))
RV64.enc(inst.i64, R, OP(f3, f7)) RV64.enc(inst.i64, R, OP(f3, f7))
# Dynamic shifts have the same masking semantics as the cton base instructions # Immediate versions for add/xor/or/and.
if inst_imm:
RV32.enc(inst_imm.i32, I, OPIMM(f3))
RV64.enc(inst_imm.i64, I, OPIMM(f3))
# There are no andiw/oriw/xoriw variations.
RV64.enc(base.iadd_imm.i32, I, OPIMM32(0b000))
# Dynamic shifts have the same masking semantics as the cton base instructions.
for inst, inst_imm, f3, f7 in [ for inst, inst_imm, f3, f7 in [
(base.ishl, base.ishl_imm, 0b001, 0b0000000), (base.ishl, base.ishl_imm, 0b001, 0b0000000),
(base.ushr, base.ushr_imm, 0b101, 0b0000000), (base.ushr, base.ushr_imm, 0b101, 0b0000000),

View File

@@ -11,6 +11,7 @@ instruction formats described in the reference:
from __future__ import absolute_import from __future__ import absolute_import
from cretonne import EncRecipe from cretonne import EncRecipe
from cretonne.formats import Binary, BinaryImm from cretonne.formats import Binary, BinaryImm
from cretonne.predicates import IsSignedInt
# 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
# instructions have 11 as the two low bits, with bits 6:2 determining the base # instructions have 11 as the two low bits, with bits 6:2 determining the base
@@ -63,3 +64,5 @@ R = EncRecipe('R', Binary)
# R-type with an immediate shift amount instead of rs2. # R-type with an immediate shift amount instead of rs2.
Rshamt = EncRecipe('Rshamt', BinaryImm) Rshamt = EncRecipe('Rshamt', BinaryImm)
I = EncRecipe('I', BinaryImm, instp=IsSignedInt(BinaryImm.imm, 12))