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):
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):
"""
@@ -983,9 +989,13 @@ class EncRecipe(object):
:py:class:`InstructionFormat`.
"""
def __init__(self, name, format):
def __init__(self, name, format, instp=None, isap=None):
self.name = name
self.format = format
self.instp = instp
self.isap = isap
if instp:
assert instp.predicate_context() == format
class Encoding(object):

View File

@@ -125,3 +125,79 @@ class Not(Predicate):
def rust_predicate(self, prec):
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 cretonne import base
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.
for inst, f3, f7 in [
(base.iadd, 0b000, 0b0000000),
(base.isub, 0b000, 0b0100000),
(base.bxor, 0b100, 0b0000000),
(base.bor, 0b110, 0b0000000),
(base.band, 0b111, 0b0000000)
for inst, inst_imm, f3, f7 in [
(base.iadd, base.iadd_imm, 0b000, 0b0000000),
(base.isub, None, 0b000, 0b0100000),
(base.bxor, base.bxor_imm, 0b100, 0b0000000),
(base.bor, base.bor_imm, 0b110, 0b0000000),
(base.band, base.band_imm, 0b111, 0b0000000)
]:
RV32.enc(inst.i32, 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 [
(base.ishl, base.ishl_imm, 0b001, 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 cretonne import EncRecipe
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
# 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.
Rshamt = EncRecipe('Rshamt', BinaryImm)
I = EncRecipe('I', BinaryImm, instp=IsSignedInt(BinaryImm.imm, 12))