Add jump encodings to RISC-V.

Fix a bug in gen_encoding.py when dealing with non-polymorphic
instructions where the type variable is None in Python, VOID in Rust.
This commit is contained in:
Jakob Stoklund Olesen
2017-04-06 15:17:57 -07:00
parent e5e5b30315
commit d2f575b54a
5 changed files with 70 additions and 12 deletions

View File

@@ -75,7 +75,8 @@ ebb0:
[-,%x7] v140 = iconst.i32 0x12345000 ; bin: 123453b7
[-,%x16] v141 = iconst.i32 0xffffffff_fedcb000 ; bin: fedcb837
jump ebb1
brz v1, ebb3
fallthrough ebb1
; Control Transfer Instructions
@@ -110,10 +111,15 @@ ebb1:
fallthrough ebb2
ebb2:
; beq x, %x0
brz v1, ebb2 ; bin: 00050063
; bne x, %x0
brnz v1, ebb2 ; bin: fe051ee3
; jal %x0, 0x00000
jump ebb2 ; bin: 0000006f
return
ebb3:
; beq x, %x0
brz v1, ebb3 ; bin: 00050063
; bne x, %x0
brnz v1, ebb3 ; bin: fe051ee3
; jal %x0, 0x1ffff4
jump ebb2 ; bin: ff5ff06f
}

View File

@@ -300,7 +300,7 @@ class Level2Table(object):
level2_doc[self.hash_table_offset].append(
'{:06x}: {}, {} entries'.format(
self.hash_table_offset,
self.ty.name,
self.ty,
self.hash_table_len))
level2_hashtables.extend(hash_table)
@@ -405,7 +405,7 @@ def emit_level1_hashtable(cpumode, level1, offt, fmt):
"""
def hash_func(level2):
# type: (Level2Table) -> int
return level2.ty.number
return level2.ty.number if level2.ty is not None else 0
hash_table = compute_quadratic(level1.tables.values(), hash_func)
with fmt.indented(
@@ -415,11 +415,12 @@ def emit_level1_hashtable(cpumode, level1, offt, fmt):
if level2:
l2l = int(math.log(level2.hash_table_len, 2))
assert l2l > 0, "Hash table too small"
tyname = level2.ty.name if level2.ty is not None else 'void'
fmt.line(
'Level1Entry ' +
'{{ ty: types::{}, log2len: {}, offset: {:#08x} }},'
.format(
level2.ty.name.upper(),
tyname.upper(),
l2l,
level2.hash_table_offset))
else:

View File

@@ -5,8 +5,8 @@ from __future__ import absolute_import
from base import instructions as base
from base.immediates import intcc
from .defs import RV32, RV64
from .recipes import OPIMM, OPIMM32, OP, OP32, LUI, BRANCH
from .recipes import JALR, R, Rshamt, Ricmp, I, Iicmp, Iret, U, SB, SBzero
from .recipes import OPIMM, OPIMM32, OP, OP32, LUI, BRANCH, JALR, JAL
from .recipes import R, Rshamt, Ricmp, I, Iicmp, Iret, U, UJ, SB, SBzero
from .settings import use_m
from cdsl.ast import Var
@@ -81,6 +81,10 @@ RV64.enc(base.imul.i32, R, OP32(0b000, 0b0000001), isap=use_m)
# Control flow.
# Unconditional branches.
RV32.enc(base.jump, UJ, JAL())
RV64.enc(base.jump, UJ, JAL())
# Conditional branches.
for cond, f3 in [
(intcc.eq, 0b000),

View File

@@ -12,7 +12,7 @@ from __future__ import absolute_import
from cdsl.isa import EncRecipe
from cdsl.predicates import IsSignedInt
from base.formats import Binary, BinaryImm, MultiAry, IntCompare, IntCompareImm
from base.formats import UnaryImm, BranchIcmp, Branch
from base.formats import UnaryImm, BranchIcmp, Branch, Jump
from .registers import GPR
# The low 7 bits of a RISC-V instruction is the base opcode. All 32-bit
@@ -47,6 +47,11 @@ def JALR(funct3=0):
return 0b11001 | (funct3 << 5)
def JAL():
# type: () -> int
return 0b11011
def OPIMM(funct3, funct7=0):
# type: (int, int) -> int
assert funct3 <= 0b111
@@ -112,6 +117,9 @@ U = EncRecipe(
'U', UnaryImm, size=4, ins=(), outs=GPR,
instp=IsSignedInt(UnaryImm.imm, 32, 12))
# UJ-type unconditional branch instructions.
UJ = EncRecipe('UJ', Jump, size=4, ins=(), outs=(), branch_range=(0, 21))
# SB-type branch instructions.
# TODO: These instructions have a +/- 4 KB branch range. How to encode that
# constraint?

View File

@@ -279,3 +279,42 @@ fn recipe_sbzero<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut
panic!("Expected Branch format: {:?}", func.dfg[inst]);
}
}
/// UJ-type jump instructions.
///
/// 31 11 6
/// imm rd opcode
/// 12 7 0
///
/// Encoding bits: `opcode[6:2]`
fn put_uj<CS: CodeSink + ?Sized>(bits: u16, imm: i64, rd: RegUnit, sink: &mut CS) {
let bits = bits as u32;
let opcode5 = bits & 0x1f;
let rd = rd as u32 & 0x1f;
assert!(is_signed_int(imm, 21, 1), "UJ out of range {:#x}", imm);
let imm = imm as u32;
// 0-6: opcode
let mut i = 0x3;
i |= opcode5 << 2;
i |= rd << 7;
// The displacement is completely hashed up.
i |= imm & 0xff000;
i |= ((imm >> 11) & 0x1) << 20;
i |= ((imm >> 1) & 0x3ff) << 21;
i |= ((imm >> 20) & 0x1) << 31;
sink.put4(i);
}
fn recipe_uj<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
if let InstructionData::Jump { destination, .. } = func.dfg[inst] {
let dest = func.offsets[destination] as i64;
let disp = dest - sink.offset() as i64;
put_uj(func.encodings[inst].bits(), disp, 0, sink);
} else {
panic!("Expected Jump format: {:?}", func.dfg[inst]);
}
}