diff --git a/meta/cretonne/__init__.py b/meta/cretonne/__init__.py index c6693a7c4a..a5e842dd8e 100644 --- a/meta/cretonne/__init__.py +++ b/meta/cretonne/__init__.py @@ -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): diff --git a/meta/cretonne/predicates.py b/meta/cretonne/predicates.py index caedae14fb..71a17eb01b 100644 --- a/meta/cretonne/predicates.py +++ b/meta/cretonne/predicates.py @@ -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 diff --git a/meta/isa/riscv/encodings.py b/meta/isa/riscv/encodings.py index 3ce5102760..099b6b5630 100644 --- a/meta/isa/riscv/encodings.py +++ b/meta/isa/riscv/encodings.py @@ -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), diff --git a/meta/isa/riscv/recipes.py b/meta/isa/riscv/recipes.py index 25ea74870f..db6d7021c8 100644 --- a/meta/isa/riscv/recipes.py +++ b/meta/isa/riscv/recipes.py @@ -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))