diff --git a/cranelift/filetests/isa/riscv/binary32.cton b/cranelift/filetests/isa/riscv/binary32.cton index ede783b7df..0c6863eae1 100644 --- a/cranelift/filetests/isa/riscv/binary32.cton +++ b/cranelift/filetests/isa/riscv/binary32.cton @@ -14,7 +14,6 @@ ebb0: ; sub [-,%x7] v12 = isub v1, v2 ; bin: 415503b3 [-,%x16] v13 = isub v2, v1 ; bin: 40aa8833 - ; TBD: slt/sltu ; and [-,%x7] v20 = band v1, v2 ; bin: 015573b3 [-,%x16] v21 = band v2, v1 ; bin: 00aaf833 @@ -33,5 +32,12 @@ ebb0: ; sra [-,%x7] v34 = sshr v1, v2 ; bin: 415553b3 [-,%x16] v35 = sshr v2, v1 ; bin: 40aad833 + ; slt + [-,%x7] v42 = icmp slt, v1, v2 ; bin: 015523b3 + [-,%x16] v43 = icmp slt, v2, v1 ; bin: 00aaa833 + ; sltu + [-,%x7] v44 = icmp ult, v1, v2 ; bin: 015533b3 + [-,%x16] v45 = icmp ult, v2, v1 ; bin: 00aab833 + return } diff --git a/lib/cretonne/meta/isa/riscv/encodings.py b/lib/cretonne/meta/isa/riscv/encodings.py index bf84c468b0..b97c92386a 100644 --- a/lib/cretonne/meta/isa/riscv/encodings.py +++ b/lib/cretonne/meta/isa/riscv/encodings.py @@ -3,9 +3,15 @@ RISC-V Encodings. """ 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, JALR, R, Rshamt, I, Iret +from .recipes import OPIMM, OPIMM32, OP, OP32, JALR, R, Rshamt, Ricmp, I, Iret from .settings import use_m +from cdsl.ast import Var + +# Dummies for instruction predicates. +x = Var('x') +y = Var('y') # Basic arithmetic binary instructions are encoded in an R-type instruction. for inst, inst_imm, f3, f7 in [ @@ -47,6 +53,13 @@ for inst, inst_imm, f3, f7 in [ RV64.enc(inst_imm.i64, Rshamt, OPIMM(f3, f7)) RV64.enc(inst_imm.i32, Rshamt, OPIMM32(f3, f7)) +# Signed and unsigned integer 'less than'. There are no 'w' variants for +# comparing 32-bit numbers in RV64. +RV32.enc(base.icmp.i32(intcc.slt, x, y), Ricmp, OP(0b010, 0b0000000)) +RV64.enc(base.icmp.i64(intcc.slt, x, y), Ricmp, OP(0b010, 0b0000000)) +RV32.enc(base.icmp.i32(intcc.ult, x, y), Ricmp, OP(0b011, 0b0000000)) +RV64.enc(base.icmp.i64(intcc.ult, x, y), Ricmp, OP(0b011, 0b0000000)) + # "M" Standard Extension for Integer Multiplication and Division. # Gated by the `use_m` flag. RV32.enc(base.imul.i32, R, OP(0b000, 0b0000001), isap=use_m) diff --git a/lib/cretonne/meta/isa/riscv/recipes.py b/lib/cretonne/meta/isa/riscv/recipes.py index 0dce091713..2fd326e5cc 100644 --- a/lib/cretonne/meta/isa/riscv/recipes.py +++ b/lib/cretonne/meta/isa/riscv/recipes.py @@ -11,7 +11,7 @@ instruction formats described in the reference: from __future__ import absolute_import from cdsl.isa import EncRecipe from cdsl.predicates import IsSignedInt -from base.formats import Binary, BinaryImm, MultiAry +from base.formats import Binary, BinaryImm, MultiAry, IntCompare from .registers import GPR # The low 7 bits of a RISC-V instruction is the base opcode. All 32-bit @@ -79,6 +79,9 @@ R = EncRecipe('R', Binary, ins=(GPR, GPR), outs=GPR) # R-type with an immediate shift amount instead of rs2. Rshamt = EncRecipe('Rshamt', BinaryImm, ins=GPR, outs=GPR) +# R-type encoding of an integer comparison. +Ricmp = EncRecipe('Ricmp', IntCompare, ins=(GPR, GPR), outs=GPR) + I = EncRecipe( 'I', BinaryImm, ins=GPR, outs=GPR, instp=IsSignedInt(BinaryImm.imm, 12)) diff --git a/lib/cretonne/src/isa/riscv/binemit.rs b/lib/cretonne/src/isa/riscv/binemit.rs index e7dcc6021f..a2e29a847e 100644 --- a/lib/cretonne/src/isa/riscv/binemit.rs +++ b/lib/cretonne/src/isa/riscv/binemit.rs @@ -2,6 +2,7 @@ use binemit::{CodeSink, bad_encoding}; use ir::{Function, Inst, InstructionData}; +use isa::RegUnit; include!(concat!(env!("OUT_DIR"), "/binemit-riscv.rs")); @@ -12,33 +13,55 @@ include!(concat!(env!("OUT_DIR"), "/binemit-riscv.rs")); /// 25 20 15 12 7 0 /// /// Encoding bits: `opcode[6:2] | (funct3 << 5) | (funct7 << 8)`. +fn put_r(bits: u16, + rs1: RegUnit, + rs2: RegUnit, + rd: RegUnit, + sink: &mut CS) { + let bits = bits as u32; + let opcode5 = bits & 0x1f; + let funct3 = (bits >> 5) & 0x7; + let funct7 = (bits >> 8) & 0x7f; + let rs1 = rs1 as u32 & 0x1f; + let rs2 = rs2 as u32 & 0x1f; + let rd = rd as u32 & 0x1f; + + // 0-6: opcode + let mut i = 0x3; + i |= opcode5 << 2; + i |= rd << 7; + i |= funct3 << 12; + i |= rs1 << 15; + i |= rs2 << 20; + i |= funct7 << 25; + + sink.put4(i); +} + fn recipe_r(func: &Function, inst: Inst, sink: &mut CS) { if let InstructionData::Binary { args, .. } = func.dfg[inst] { - let bits = func.encodings[inst].bits(); - let rs1 = func.locations[args[0]].unwrap_reg(); - let rs2 = func.locations[args[1]].unwrap_reg(); - let rd = func.locations[func.dfg.first_result(inst)].unwrap_reg(); - - // 0-6: opcode - let mut i = 0x3; - i |= (bits as u32 & 0x1f) << 2; - // 7-11: rd - i |= (rd as u32 & 0x1f) << 7; - // 12-14: funct3 - i |= ((bits as u32 >> 5) & 0x7) << 12; - // 15-19: rs1 - i |= (rs1 as u32 & 0x1f) << 15; - // 20-24: rs1 - i |= (rs2 as u32 & 0x1f) << 20; - // 25-31: funct7 - i |= ((bits as u32 >> 8) & 0x7f) << 25; - - sink.put4(i); + put_r(func.encodings[inst].bits(), + func.locations[args[0]].unwrap_reg(), + func.locations[args[1]].unwrap_reg(), + func.locations[func.dfg.first_result(inst)].unwrap_reg(), + sink); } else { panic!("Expected Binary format: {:?}", func.dfg[inst]); } } +fn recipe_ricmp(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::IntCompare { args, .. } = func.dfg[inst] { + put_r(func.encodings[inst].bits(), + func.locations[args[0]].unwrap_reg(), + func.locations[args[1]].unwrap_reg(), + func.locations[func.dfg.first_result(inst)].unwrap_reg(), + sink); + } else { + panic!("Expected IntCompare format: {:?}", func.dfg[inst]); + } +} + fn recipe_rshamt(_func: &Function, _inst: Inst, _sink: &mut CS) { unimplemented!() } diff --git a/lib/cretonne/src/isa/riscv/enc_tables.rs b/lib/cretonne/src/isa/riscv/enc_tables.rs index f02ccf80ba..7940fce004 100644 --- a/lib/cretonne/src/isa/riscv/enc_tables.rs +++ b/lib/cretonne/src/isa/riscv/enc_tables.rs @@ -1,5 +1,6 @@ //! Encoding tables for RISC-V. +use ir::condcodes::IntCC; use ir::{Opcode, InstructionData}; use ir::types; use predicates;