Move library crates under 'lib/'.
Give these crates each a more standard directory layout with sources in a 'src' sub-sirectory and Cargo.toml in the top lib/foo directory. Add license and description fields to each. The build script for the cretonne crate now lives in 'lib/cretonne/build.rs' separating it from the normal library sources under 'lib/cretonne/src'.
This commit is contained in:
152
lib/cretonne/src/isa/enc_tables.rs
Normal file
152
lib/cretonne/src/isa/enc_tables.rs
Normal file
@@ -0,0 +1,152 @@
|
||||
//! Support types for generated encoding tables.
|
||||
//!
|
||||
//! This module contains types and functions for working with the encoding tables generated by
|
||||
//! `meta/gen_encoding.py`.
|
||||
use ir::{Type, Opcode};
|
||||
use isa::Encoding;
|
||||
use constant_hash::{Table, probe};
|
||||
|
||||
/// Level 1 hash table entry.
|
||||
///
|
||||
/// One level 1 hash table is generated per CPU mode. This table is keyed by the controlling type
|
||||
/// variable, using `VOID` for non-polymorphic instructions.
|
||||
///
|
||||
/// The hash table values are references to level 2 hash tables, encoded as an offset in `LEVEL2`
|
||||
/// where the table begins, and the binary logarithm of its length. All the level 2 hash tables
|
||||
/// have a power-of-two size.
|
||||
///
|
||||
/// Entries are generic over the offset type. It will typically be `u32` or `u16`, depending on the
|
||||
/// size of the `LEVEL2` table. A `u16` offset allows entries to shrink to 32 bits each, but some
|
||||
/// ISAs may have tables so large that `u32` offsets are needed.
|
||||
///
|
||||
/// Empty entries are encoded with a 0 `log2len`. This is on the assumption that no level 2 tables
|
||||
/// have only a single entry.
|
||||
pub struct Level1Entry<OffT: Into<u32> + Copy> {
|
||||
pub ty: Type,
|
||||
pub log2len: u8,
|
||||
pub offset: OffT,
|
||||
}
|
||||
|
||||
impl<OffT: Into<u32> + Copy> Table<Type> for [Level1Entry<OffT>] {
|
||||
fn len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn key(&self, idx: usize) -> Option<Type> {
|
||||
if self[idx].log2len != 0 {
|
||||
Some(self[idx].ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Level 2 hash table entry.
|
||||
///
|
||||
/// The second level hash tables are keyed by `Opcode`, and contain an offset into the `ENCLISTS`
|
||||
/// table where the encoding recipes for the instrution are stored.
|
||||
///
|
||||
/// Entries are generic over the offset type which depends on the size of `ENCLISTS`. A `u16`
|
||||
/// offset allows the entries to be only 32 bits each. There is no benefit to dropping down to `u8`
|
||||
/// for tiny ISAs. The entries won't shrink below 32 bits since the opcode is expected to be 16
|
||||
/// bits.
|
||||
///
|
||||
/// Empty entries are encoded with a `NotAnOpcode` `opcode` field.
|
||||
pub struct Level2Entry<OffT: Into<u32> + Copy> {
|
||||
pub opcode: Opcode,
|
||||
pub offset: OffT,
|
||||
}
|
||||
|
||||
impl<OffT: Into<u32> + Copy> Table<Opcode> for [Level2Entry<OffT>] {
|
||||
fn len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn key(&self, idx: usize) -> Option<Opcode> {
|
||||
let opc = self[idx].opcode;
|
||||
if opc != Opcode::NotAnOpcode {
|
||||
Some(opc)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Two-level hash table lookup.
|
||||
///
|
||||
/// Given the controlling type variable and instruction opcode, find the corresponding encoding
|
||||
/// list.
|
||||
///
|
||||
/// Returns an offset into the ISA's `ENCLIST` table, or `None` if the opcode/type combination is
|
||||
/// not legal.
|
||||
pub fn lookup_enclist<OffT1, OffT2>(ctrl_typevar: Type,
|
||||
opcode: Opcode,
|
||||
level1_table: &[Level1Entry<OffT1>],
|
||||
level2_table: &[Level2Entry<OffT2>])
|
||||
-> Option<usize>
|
||||
where OffT1: Into<u32> + Copy,
|
||||
OffT2: Into<u32> + Copy
|
||||
{
|
||||
probe(level1_table, ctrl_typevar, ctrl_typevar.index()).and_then(|l1idx| {
|
||||
let l1ent = &level1_table[l1idx];
|
||||
let l2off = l1ent.offset.into() as usize;
|
||||
let l2tab = &level2_table[l2off..l2off + (1 << l1ent.log2len)];
|
||||
probe(l2tab, opcode, opcode as usize).map(|l2idx| l2tab[l2idx].offset.into() as usize)
|
||||
})
|
||||
}
|
||||
|
||||
/// Encoding list entry.
|
||||
///
|
||||
/// Encoding lists are represented as sequences of u16 words.
|
||||
pub type EncListEntry = u16;
|
||||
|
||||
/// Number of bits used to represent a predicate. c.f. `meta.gen_encoding.py`.
|
||||
const PRED_BITS: u8 = 12;
|
||||
const PRED_MASK: EncListEntry = (1 << PRED_BITS) - 1;
|
||||
|
||||
/// The match-always instruction predicate. c.f. `meta.gen_encoding.py`.
|
||||
const CODE_ALWAYS: EncListEntry = PRED_MASK;
|
||||
|
||||
/// The encoding list terminator.
|
||||
const CODE_FAIL: EncListEntry = 0xffff;
|
||||
|
||||
/// Find the most general encoding of `inst`.
|
||||
///
|
||||
/// Given an encoding list offset as returned by `lookup_enclist` above, search the encoding list
|
||||
/// for the most general encoding that applies to `inst`. The encoding lists are laid out such that
|
||||
/// this is the last valid entry in the list.
|
||||
///
|
||||
/// This function takes two closures that are used to evaluate predicates:
|
||||
/// - `instp` is passed an instruction predicate number to be evaluated on the current instruction.
|
||||
/// - `isap` is passed an ISA predicate number to evaluate.
|
||||
///
|
||||
/// Returns the corresponding encoding, or `None` if no list entries are satisfied by `inst`.
|
||||
pub fn general_encoding<InstP, IsaP>(offset: usize,
|
||||
enclist: &[EncListEntry],
|
||||
instp: InstP,
|
||||
isap: IsaP)
|
||||
-> Option<Encoding>
|
||||
where InstP: Fn(EncListEntry) -> bool,
|
||||
IsaP: Fn(EncListEntry) -> bool
|
||||
{
|
||||
let mut found = None;
|
||||
let mut pos = offset;
|
||||
while enclist[pos] != CODE_FAIL {
|
||||
let pred = enclist[pos];
|
||||
if pred <= CODE_ALWAYS {
|
||||
// This is an instruction predicate followed by recipe and encbits entries.
|
||||
if pred == CODE_ALWAYS || instp(pred) {
|
||||
found = Some(Encoding::new(enclist[pos + 1], enclist[pos + 2]))
|
||||
}
|
||||
pos += 3;
|
||||
} else {
|
||||
// This is an ISA predicate entry.
|
||||
pos += 1;
|
||||
if !isap(pred & PRED_MASK) {
|
||||
// ISA predicate failed, skip the next N entries.
|
||||
pos += 3 * (pred >> PRED_BITS) as usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
found
|
||||
}
|
||||
78
lib/cretonne/src/isa/encoding.rs
Normal file
78
lib/cretonne/src/isa/encoding.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
//! The `Encoding` struct.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
/// Bits needed to encode an instruction as binary machine code.
|
||||
///
|
||||
/// The encoding consists of two parts, both specific to the target ISA: An encoding *recipe*, and
|
||||
/// encoding *bits*. The recipe determines the native instruction format and the mapping of
|
||||
/// operands to encoded bits. The encoding bits provide additional information to the recipe,
|
||||
/// typically parts of the opcode.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct Encoding {
|
||||
recipe: u16,
|
||||
bits: u16,
|
||||
}
|
||||
|
||||
impl Encoding {
|
||||
/// Create a new `Encoding` containing `(recipe, bits)`.
|
||||
pub fn new(recipe: u16, bits: u16) -> Encoding {
|
||||
Encoding {
|
||||
recipe: recipe,
|
||||
bits: bits,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the recipe number in this encoding.
|
||||
pub fn recipe(self) -> usize {
|
||||
self.recipe as usize
|
||||
}
|
||||
|
||||
/// Get the recipe-specific encoding bits.
|
||||
pub fn bits(self) -> u16 {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Is this a legal encoding, or the default placeholder?
|
||||
pub fn is_legal(self) -> bool {
|
||||
self != Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// The default encoding is the illegal one.
|
||||
impl Default for Encoding {
|
||||
fn default() -> Self {
|
||||
Self::new(0xffff, 0xffff)
|
||||
}
|
||||
}
|
||||
|
||||
/// ISA-independent display of an encoding.
|
||||
impl fmt::Display for Encoding {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.is_legal() {
|
||||
write!(f, "{}#{:02x}", self.recipe, self.bits)
|
||||
} else {
|
||||
write!(f, "-")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Temporary object that holds enough context to properly display an encoding.
|
||||
/// This is meant to be created by `TargetIsa::display_enc()`.
|
||||
pub struct DisplayEncoding {
|
||||
pub encoding: Encoding,
|
||||
pub recipe_names: &'static [&'static str],
|
||||
}
|
||||
|
||||
impl fmt::Display for DisplayEncoding {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.encoding.is_legal() {
|
||||
write!(f,
|
||||
"{}#{:02x}",
|
||||
self.recipe_names[self.encoding.recipe()],
|
||||
self.encoding.bits)
|
||||
} else {
|
||||
write!(f, "-")
|
||||
}
|
||||
}
|
||||
}
|
||||
118
lib/cretonne/src/isa/mod.rs
Normal file
118
lib/cretonne/src/isa/mod.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
//! Instruction Set Architectures.
|
||||
//!
|
||||
//! The `isa` module provides a `TargetIsa` trait which provides the behavior specialization needed
|
||||
//! by the ISA-independent code generator. The sub-modules of this module provide definitions for
|
||||
//! the instruction sets that Cretonne can target. Each sub-module has it's own implementation of
|
||||
//! `TargetIsa`.
|
||||
//!
|
||||
//! # Constructing a `TargetIsa` instance
|
||||
//!
|
||||
//! The target ISA is built from the following information:
|
||||
//!
|
||||
//! - The name of the target ISA as a string. Cretonne is a cross-compiler, so the ISA to target
|
||||
//! can be selected dynamically. Individual ISAs can be left out when Cretonne is compiled, so a
|
||||
//! string is used to identify the proper sub-module.
|
||||
//! - Values for settings that apply to all ISAs. This is represented by a `settings::Flags`
|
||||
//! instance.
|
||||
//! - Values for ISA-specific settings.
|
||||
//!
|
||||
//! The `isa::lookup()` function is the main entry point which returns an `isa::Builder`
|
||||
//! appropriate for the requested ISA:
|
||||
//!
|
||||
//! ```
|
||||
//! use cretonne::settings::{self, Configurable};
|
||||
//! use cretonne::isa;
|
||||
//!
|
||||
//! let shared_builder = settings::builder();
|
||||
//! let shared_flags = settings::Flags::new(&shared_builder);
|
||||
//!
|
||||
//! match isa::lookup("riscv") {
|
||||
//! None => {
|
||||
//! // The RISC-V target ISA is not available.
|
||||
//! }
|
||||
//! Some(mut isa_builder) => {
|
||||
//! isa_builder.set("supports_m", "on");
|
||||
//! let isa = isa_builder.finish(shared_flags);
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! The configured target ISA trait object is a `Box<TargetIsa>` which can be used for multiple
|
||||
//! concurrent function compilations.
|
||||
|
||||
pub use isa::encoding::Encoding;
|
||||
use settings;
|
||||
use ir::{InstructionData, DataFlowGraph};
|
||||
|
||||
pub mod riscv;
|
||||
mod encoding;
|
||||
mod enc_tables;
|
||||
|
||||
/// Look for a supported ISA with the given `name`.
|
||||
/// Return a builder that can create a corresponding `TargetIsa`.
|
||||
pub fn lookup(name: &str) -> Option<Builder> {
|
||||
match name {
|
||||
"riscv" => riscv_builder(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// Make a builder for RISC-V.
|
||||
fn riscv_builder() -> Option<Builder> {
|
||||
Some(riscv::isa_builder())
|
||||
}
|
||||
|
||||
/// Builder for a `TargetIsa`.
|
||||
/// Modify the ISA-specific settings before creating the `TargetIsa` trait object with `finish`.
|
||||
pub struct Builder {
|
||||
setup: settings::Builder,
|
||||
constructor: fn(settings::Flags, &settings::Builder) -> Box<TargetIsa>,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
/// Combine the ISA-specific settings with the provided ISA-independent settings and allocate a
|
||||
/// fully configured `TargetIsa` trait object.
|
||||
pub fn finish(self, shared_flags: settings::Flags) -> Box<TargetIsa> {
|
||||
(self.constructor)(shared_flags, &self.setup)
|
||||
}
|
||||
}
|
||||
|
||||
impl settings::Configurable for Builder {
|
||||
fn set(&mut self, name: &str, value: &str) -> settings::Result<()> {
|
||||
self.setup.set(name, value)
|
||||
}
|
||||
|
||||
fn set_bool(&mut self, name: &str, value: bool) -> settings::Result<()> {
|
||||
self.setup.set_bool(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TargetIsa {
|
||||
/// Get the name of this ISA.
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
/// Get the ISA-independent flags that were used to make this trait object.
|
||||
fn flags(&self) -> &settings::Flags;
|
||||
|
||||
/// Encode an instruction after determining it is legal.
|
||||
///
|
||||
/// If `inst` can legally be encoded in this ISA, produce the corresponding `Encoding` object.
|
||||
/// Otherwise, return `None`.
|
||||
///
|
||||
/// This is also the main entry point for determining if an instruction is legal.
|
||||
fn encode(&self, dfg: &DataFlowGraph, inst: &InstructionData) -> Option<Encoding>;
|
||||
|
||||
/// Get a static array of names associated with encoding recipes in this ISA. Encoding recipes
|
||||
/// are numbered starting from 0, corresponding to indexes into th name array.
|
||||
///
|
||||
/// This is just used for printing and parsing encodings in the textual IL format.
|
||||
fn recipe_names(&self) -> &'static [&'static str];
|
||||
|
||||
/// Create an object that can display an ISA-dependent encoding properly.
|
||||
fn display_enc(&self, enc: Encoding) -> encoding::DisplayEncoding {
|
||||
encoding::DisplayEncoding {
|
||||
encoding: enc,
|
||||
recipe_names: self.recipe_names(),
|
||||
}
|
||||
}
|
||||
}
|
||||
14
lib/cretonne/src/isa/riscv/enc_tables.rs
Normal file
14
lib/cretonne/src/isa/riscv/enc_tables.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
//! Encoding tables for RISC-V.
|
||||
|
||||
use ir::{Opcode, InstructionData};
|
||||
use ir::instructions::InstructionFormat;
|
||||
use ir::types;
|
||||
use predicates;
|
||||
use isa::enc_tables::{Level1Entry, Level2Entry};
|
||||
|
||||
// Include the generated encoding tables:
|
||||
// - `LEVEL1_RV32`
|
||||
// - `LEVEL1_RV64`
|
||||
// - `LEVEL2`
|
||||
// - `ENCLIST`
|
||||
include!(concat!(env!("OUT_DIR"), "/encoding-riscv.rs"));
|
||||
206
lib/cretonne/src/isa/riscv/mod.rs
Normal file
206
lib/cretonne/src/isa/riscv/mod.rs
Normal file
@@ -0,0 +1,206 @@
|
||||
//! RISC-V Instruction Set Architecture.
|
||||
|
||||
pub mod settings;
|
||||
mod enc_tables;
|
||||
|
||||
use super::super::settings as shared_settings;
|
||||
use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, general_encoding};
|
||||
use isa::Builder as IsaBuilder;
|
||||
use isa::{TargetIsa, Encoding};
|
||||
use ir::{InstructionData, DataFlowGraph};
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Isa {
|
||||
shared_flags: shared_settings::Flags,
|
||||
isa_flags: settings::Flags,
|
||||
cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
|
||||
}
|
||||
|
||||
pub fn isa_builder() -> IsaBuilder {
|
||||
IsaBuilder {
|
||||
setup: settings::builder(),
|
||||
constructor: isa_constructor,
|
||||
}
|
||||
}
|
||||
|
||||
fn isa_constructor(shared_flags: shared_settings::Flags,
|
||||
builder: &shared_settings::Builder)
|
||||
-> Box<TargetIsa> {
|
||||
let level1 = if shared_flags.is_64bit() {
|
||||
&enc_tables::LEVEL1_RV64[..]
|
||||
} else {
|
||||
&enc_tables::LEVEL1_RV32[..]
|
||||
};
|
||||
Box::new(Isa {
|
||||
isa_flags: settings::Flags::new(&shared_flags, builder),
|
||||
shared_flags: shared_flags,
|
||||
cpumode: level1,
|
||||
})
|
||||
}
|
||||
|
||||
impl TargetIsa for Isa {
|
||||
fn name(&self) -> &'static str {
|
||||
"riscv"
|
||||
}
|
||||
|
||||
fn flags(&self) -> &shared_settings::Flags {
|
||||
&self.shared_flags
|
||||
}
|
||||
|
||||
fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Option<Encoding> {
|
||||
lookup_enclist(inst.first_type(),
|
||||
inst.opcode(),
|
||||
self.cpumode,
|
||||
&enc_tables::LEVEL2[..])
|
||||
.and_then(|enclist_offset| {
|
||||
general_encoding(enclist_offset,
|
||||
&enc_tables::ENCLISTS[..],
|
||||
|instp| enc_tables::check_instp(inst, instp),
|
||||
|isap| self.isa_flags.numbered_predicate(isap as usize))
|
||||
})
|
||||
}
|
||||
|
||||
fn recipe_names(&self) -> &'static [&'static str] {
|
||||
&enc_tables::RECIPE_NAMES[..]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use settings::{self, Configurable};
|
||||
use isa;
|
||||
use ir::{DataFlowGraph, InstructionData, Opcode};
|
||||
use ir::{types, immediates};
|
||||
|
||||
fn encstr(isa: &isa::TargetIsa, enc: isa::Encoding) -> String {
|
||||
isa.display_enc(enc).to_string()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_64bitenc() {
|
||||
let mut shared_builder = settings::builder();
|
||||
shared_builder.set_bool("is_64bit", true).unwrap();
|
||||
let shared_flags = settings::Flags::new(&shared_builder);
|
||||
let isa = isa::lookup("riscv").unwrap().finish(shared_flags);
|
||||
|
||||
let mut dfg = DataFlowGraph::new();
|
||||
let ebb = dfg.make_ebb();
|
||||
let arg64 = dfg.append_ebb_arg(ebb, types::I64);
|
||||
let arg32 = dfg.append_ebb_arg(ebb, types::I32);
|
||||
|
||||
// Try to encode iadd_imm.i64 vx1, -10.
|
||||
let inst64 = InstructionData::BinaryImm {
|
||||
opcode: Opcode::IaddImm,
|
||||
ty: types::I64,
|
||||
arg: arg64,
|
||||
imm: immediates::Imm64::new(-10),
|
||||
};
|
||||
|
||||
// ADDI is I/0b00100
|
||||
assert_eq!(encstr(&*isa, isa.encode(&dfg, &inst64).unwrap()), "I#04");
|
||||
|
||||
// Try to encode iadd_imm.i64 vx1, -10000.
|
||||
let inst64_large = InstructionData::BinaryImm {
|
||||
opcode: Opcode::IaddImm,
|
||||
ty: types::I64,
|
||||
arg: arg64,
|
||||
imm: immediates::Imm64::new(-10000),
|
||||
};
|
||||
|
||||
// Immediate is out of range for ADDI.
|
||||
assert_eq!(isa.encode(&dfg, &inst64_large), None);
|
||||
|
||||
// Create an iadd_imm.i32 which is encodable in RV64.
|
||||
let inst32 = InstructionData::BinaryImm {
|
||||
opcode: Opcode::IaddImm,
|
||||
ty: types::I32,
|
||||
arg: arg32,
|
||||
imm: immediates::Imm64::new(10),
|
||||
};
|
||||
|
||||
// ADDIW is I/0b00110
|
||||
assert_eq!(encstr(&*isa, isa.encode(&dfg, &inst32).unwrap()), "I#06");
|
||||
}
|
||||
|
||||
// Same as above, but for RV32.
|
||||
#[test]
|
||||
fn test_32bitenc() {
|
||||
let mut shared_builder = settings::builder();
|
||||
shared_builder.set_bool("is_64bit", false).unwrap();
|
||||
let shared_flags = settings::Flags::new(&shared_builder);
|
||||
let isa = isa::lookup("riscv").unwrap().finish(shared_flags);
|
||||
|
||||
let mut dfg = DataFlowGraph::new();
|
||||
let ebb = dfg.make_ebb();
|
||||
let arg64 = dfg.append_ebb_arg(ebb, types::I64);
|
||||
let arg32 = dfg.append_ebb_arg(ebb, types::I32);
|
||||
|
||||
// Try to encode iadd_imm.i64 vx1, -10.
|
||||
let inst64 = InstructionData::BinaryImm {
|
||||
opcode: Opcode::IaddImm,
|
||||
ty: types::I64,
|
||||
arg: arg64,
|
||||
imm: immediates::Imm64::new(-10),
|
||||
};
|
||||
|
||||
// ADDI is I/0b00100
|
||||
assert_eq!(isa.encode(&dfg, &inst64), None);
|
||||
|
||||
// Try to encode iadd_imm.i64 vx1, -10000.
|
||||
let inst64_large = InstructionData::BinaryImm {
|
||||
opcode: Opcode::IaddImm,
|
||||
ty: types::I64,
|
||||
arg: arg64,
|
||||
imm: immediates::Imm64::new(-10000),
|
||||
};
|
||||
|
||||
// Immediate is out of range for ADDI.
|
||||
assert_eq!(isa.encode(&dfg, &inst64_large), None);
|
||||
|
||||
// Create an iadd_imm.i32 which is encodable in RV32.
|
||||
let inst32 = InstructionData::BinaryImm {
|
||||
opcode: Opcode::IaddImm,
|
||||
ty: types::I32,
|
||||
arg: arg32,
|
||||
imm: immediates::Imm64::new(10),
|
||||
};
|
||||
|
||||
// ADDI is I/0b00100
|
||||
assert_eq!(encstr(&*isa, isa.encode(&dfg, &inst32).unwrap()), "I#04");
|
||||
|
||||
// Create an imul.i32 which is encodable in RV32, but only when use_m is true.
|
||||
let mul32 = InstructionData::Binary {
|
||||
opcode: Opcode::Imul,
|
||||
ty: types::I32,
|
||||
args: [arg32, arg32],
|
||||
};
|
||||
|
||||
assert_eq!(isa.encode(&dfg, &mul32), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rv32m() {
|
||||
let mut shared_builder = settings::builder();
|
||||
shared_builder.set_bool("is_64bit", false).unwrap();
|
||||
let shared_flags = settings::Flags::new(&shared_builder);
|
||||
|
||||
// Set the supports_m stting which in turn enables the use_m predicate that unlocks
|
||||
// encodings for imul.
|
||||
let mut isa_builder = isa::lookup("riscv").unwrap();
|
||||
isa_builder.set_bool("supports_m", true).unwrap();
|
||||
|
||||
let isa = isa_builder.finish(shared_flags);
|
||||
|
||||
let mut dfg = DataFlowGraph::new();
|
||||
let ebb = dfg.make_ebb();
|
||||
let arg32 = dfg.append_ebb_arg(ebb, types::I32);
|
||||
|
||||
// Create an imul.i32 which is encodable in RV32M.
|
||||
let mul32 = InstructionData::Binary {
|
||||
opcode: Opcode::Imul,
|
||||
ty: types::I32,
|
||||
args: [arg32, arg32],
|
||||
};
|
||||
assert_eq!(encstr(&*isa, isa.encode(&dfg, &mul32).unwrap()), "R#10c");
|
||||
}
|
||||
}
|
||||
49
lib/cretonne/src/isa/riscv/settings.rs
Normal file
49
lib/cretonne/src/isa/riscv/settings.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
//! RISC-V Settings.
|
||||
|
||||
use settings::{self, detail, Builder};
|
||||
use std::fmt;
|
||||
|
||||
// Include code generated by `meta/gen_settings.py`. This file contains a public `Flags` struct
|
||||
// with an impl for all of the settings defined in `meta/cretonne/settings.py`.
|
||||
include!(concat!(env!("OUT_DIR"), "/settings-riscv.rs"));
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{builder, Flags};
|
||||
use settings::{self, Configurable};
|
||||
|
||||
#[test]
|
||||
fn display_default() {
|
||||
let shared = settings::Flags::new(&settings::builder());
|
||||
let b = builder();
|
||||
let f = Flags::new(&shared, &b);
|
||||
assert_eq!(f.to_string(),
|
||||
"[riscv]\n\
|
||||
supports_m = false\n\
|
||||
supports_a = false\n\
|
||||
supports_f = false\n\
|
||||
supports_d = false\n\
|
||||
enable_m = true\n");
|
||||
// Predicates are not part of the Display output.
|
||||
assert_eq!(f.full_float(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn predicates() {
|
||||
let shared = settings::Flags::new(&settings::builder());
|
||||
let mut b = builder();
|
||||
b.set_bool("supports_f", true).unwrap();
|
||||
b.set_bool("supports_d", true).unwrap();
|
||||
let f = Flags::new(&shared, &b);
|
||||
assert_eq!(f.full_float(), true);
|
||||
|
||||
let mut sb = settings::builder();
|
||||
sb.set_bool("enable_simd", false).unwrap();
|
||||
let shared = settings::Flags::new(&sb);
|
||||
let mut b = builder();
|
||||
b.set_bool("supports_f", true).unwrap();
|
||||
b.set_bool("supports_d", true).unwrap();
|
||||
let f = Flags::new(&shared, &b);
|
||||
assert_eq!(f.full_float(), false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user