diff --git a/filetests/isa/riscv/binary32.cton b/filetests/isa/riscv/binary32.cton index 4c9f9439b9..d34fe34e21 100644 --- a/filetests/isa/riscv/binary32.cton +++ b/filetests/isa/riscv/binary32.cton @@ -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 } diff --git a/lib/cretonne/meta/gen_encoding.py b/lib/cretonne/meta/gen_encoding.py index a68710f540..706ad46780 100644 --- a/lib/cretonne/meta/gen_encoding.py +++ b/lib/cretonne/meta/gen_encoding.py @@ -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: diff --git a/lib/cretonne/meta/isa/riscv/encodings.py b/lib/cretonne/meta/isa/riscv/encodings.py index 162ccbd3ea..21ff09e177 100644 --- a/lib/cretonne/meta/isa/riscv/encodings.py +++ b/lib/cretonne/meta/isa/riscv/encodings.py @@ -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), diff --git a/lib/cretonne/meta/isa/riscv/recipes.py b/lib/cretonne/meta/isa/riscv/recipes.py index 63ca9b78ba..e30922613f 100644 --- a/lib/cretonne/meta/isa/riscv/recipes.py +++ b/lib/cretonne/meta/isa/riscv/recipes.py @@ -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? diff --git a/lib/cretonne/src/isa/riscv/binemit.rs b/lib/cretonne/src/isa/riscv/binemit.rs index a392d76a07..e4cc5c05c6 100644 --- a/lib/cretonne/src/isa/riscv/binemit.rs +++ b/lib/cretonne/src/isa/riscv/binemit.rs @@ -279,3 +279,42 @@ fn recipe_sbzero(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(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(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]); + } +}