diff --git a/lib/cretonne/meta/base/settings.py b/lib/cretonne/meta/base/settings.py index c6f87f7fbb..1f7e21668b 100644 --- a/lib/cretonne/meta/base/settings.py +++ b/lib/cretonne/meta/base/settings.py @@ -20,6 +20,8 @@ opt_level = EnumSetting( is_64bit = BoolSetting("Enable 64-bit code generation") +is_compressed = BoolSetting("Enable compressed instructions") + enable_float = BoolSetting( """Enable the use of floating-point instructions""", default=True) diff --git a/lib/cretonne/meta/gen_encoding.py b/lib/cretonne/meta/gen_encoding.py index e404fb79ec..8477f31de2 100644 --- a/lib/cretonne/meta/gen_encoding.py +++ b/lib/cretonne/meta/gen_encoding.py @@ -91,6 +91,8 @@ def emit_instps(instps, fmt): Emit a function for matching instruction predicates. """ + if not instps: + fmt.line('#[allow(unused_variables)]') with fmt.indented( 'pub fn check_instp(inst: &InstructionData, instp_idx: u16) ' + '-> bool {', '}'): diff --git a/lib/cretonne/meta/gen_settings.py b/lib/cretonne/meta/gen_settings.py index 74aa0dca48..3f435c8fc3 100644 --- a/lib/cretonne/meta/gen_settings.py +++ b/lib/cretonne/meta/gen_settings.py @@ -192,6 +192,7 @@ def gen_constructor(sgrp, parent, fmt): p = sgrp.parent args = '{}: &{}::Flags, {}'.format(p.name, p.qual_mod, args) fmt.doc_comment('Create flags {} settings group.'.format(sgrp.name)) + fmt.line('#[allow(unused_variables)]') with fmt.indented( 'pub fn new({}) -> Flags {{'.format(args), '}'): fmt.line('let bvec = builder.state_for("{}");'.format(sgrp.name)) @@ -259,9 +260,8 @@ def generate(isas, out_dir): # Generate ISA-specific settings. for isa in isas: - if isa.settings: - isa.settings.qual_mod = 'isa::{}::settings'.format( - isa.settings.name) - fmt = srcgen.Formatter() - gen_group(isa.settings, fmt) - fmt.update_file('settings-{}.rs'.format(isa.name), out_dir) + isa.settings.qual_mod = 'isa::{}::settings'.format( + isa.settings.name) + fmt = srcgen.Formatter() + gen_group(isa.settings, fmt) + fmt.update_file('settings-{}.rs'.format(isa.name), out_dir) diff --git a/lib/cretonne/meta/isa/arm32/__init__.py b/lib/cretonne/meta/isa/arm32/__init__.py index 52f150b8e1..d2de00667a 100644 --- a/lib/cretonne/meta/isa/arm32/__init__.py +++ b/lib/cretonne/meta/isa/arm32/__init__.py @@ -8,7 +8,7 @@ This target ISA generates code for ARMv7 and ARMv8 CPUs in 32-bit mode from __future__ import absolute_import from . import defs -from . import registers # noqa +from . import settings, registers # noqa # Re-export the primary target ISA definition. ISA = defs.ISA.finish() diff --git a/lib/cretonne/meta/isa/arm32/registers.py b/lib/cretonne/meta/isa/arm32/registers.py index 3084c2bf98..af031e145b 100644 --- a/lib/cretonne/meta/isa/arm32/registers.py +++ b/lib/cretonne/meta/isa/arm32/registers.py @@ -6,15 +6,7 @@ from cdsl.registers import RegBank, RegClass from .defs import ISA -# Special register units: -# - r15 is the program counter. -# - r14 is the link register. -# - r13 is usually the stack pointer. -IntRegs = RegBank( - 'IntRegs', ISA, - 'General purpose registers', - units=16, prefix='r') - +# Define the larger float bank first to avoid the alignment gap. FloatRegs = RegBank( 'FloatRegs', ISA, r""" Floating point registers. @@ -28,6 +20,15 @@ FloatRegs = RegBank( """, units=64, prefix='s') +# Special register units: +# - r15 is the program counter. +# - r14 is the link register. +# - r13 is usually the stack pointer. +IntRegs = RegBank( + 'IntRegs', ISA, + 'General purpose registers', + units=16, prefix='r') + GPR = RegClass('GPR', IntRegs) S = RegClass('S', FloatRegs, count=32) D = RegClass('D', FloatRegs, width=2) diff --git a/lib/cretonne/meta/isa/arm32/settings.py b/lib/cretonne/meta/isa/arm32/settings.py new file mode 100644 index 0000000000..5cc948cf2d --- /dev/null +++ b/lib/cretonne/meta/isa/arm32/settings.py @@ -0,0 +1,11 @@ +""" +ARM32 settings. +""" +from __future__ import absolute_import +from cdsl.settings import SettingGroup +import base.settings as shared +from .defs import ISA + +ISA.settings = SettingGroup('arm32', parent=shared.group) + +ISA.settings.close(globals()) diff --git a/lib/cretonne/meta/isa/arm64/__init__.py b/lib/cretonne/meta/isa/arm64/__init__.py index 75f5e85f38..3dd69feb4b 100644 --- a/lib/cretonne/meta/isa/arm64/__init__.py +++ b/lib/cretonne/meta/isa/arm64/__init__.py @@ -7,7 +7,7 @@ ARMv8 CPUs running the Aarch64 architecture. from __future__ import absolute_import from . import defs -from . import registers # noqa +from . import settings, registers # noqa # Re-export the primary target ISA definition. ISA = defs.ISA.finish() diff --git a/lib/cretonne/meta/isa/arm64/settings.py b/lib/cretonne/meta/isa/arm64/settings.py new file mode 100644 index 0000000000..9a2fc13dc7 --- /dev/null +++ b/lib/cretonne/meta/isa/arm64/settings.py @@ -0,0 +1,11 @@ +""" +ARM64 settings. +""" +from __future__ import absolute_import +from cdsl.settings import SettingGroup +import base.settings as shared +from .defs import ISA + +ISA.settings = SettingGroup('arm64', parent=shared.group) + +ISA.settings.close(globals()) diff --git a/lib/cretonne/meta/isa/intel/__init__.py b/lib/cretonne/meta/isa/intel/__init__.py index 81948699d2..6aea0fd288 100644 --- a/lib/cretonne/meta/isa/intel/__init__.py +++ b/lib/cretonne/meta/isa/intel/__init__.py @@ -17,7 +17,7 @@ is no x87 floating point support. from __future__ import absolute_import from . import defs -from . import registers # noqa +from . import settings, registers # noqa # Re-export the primary target ISA definition. ISA = defs.ISA.finish() diff --git a/lib/cretonne/meta/isa/intel/settings.py b/lib/cretonne/meta/isa/intel/settings.py new file mode 100644 index 0000000000..42e1a0ab99 --- /dev/null +++ b/lib/cretonne/meta/isa/intel/settings.py @@ -0,0 +1,11 @@ +""" +Intel settings. +""" +from __future__ import absolute_import +from cdsl.settings import SettingGroup +import base.settings as shared +from .defs import ISA + +ISA.settings = SettingGroup('intel', parent=shared.group) + +ISA.settings.close(globals()) diff --git a/lib/cretonne/src/isa/arm32/enc_tables.rs b/lib/cretonne/src/isa/arm32/enc_tables.rs new file mode 100644 index 0000000000..e40362a32f --- /dev/null +++ b/lib/cretonne/src/isa/arm32/enc_tables.rs @@ -0,0 +1,8 @@ +//! Encoding tables for ARM32 ISA. + +use ir::InstructionData; +use ir::instructions::InstructionFormat; +use ir::types; +use isa::enc_tables::{Level1Entry, Level2Entry}; + +include!(concat!(env!("OUT_DIR"), "/encoding-arm32.rs")); diff --git a/lib/cretonne/src/isa/arm32/mod.rs b/lib/cretonne/src/isa/arm32/mod.rs new file mode 100644 index 0000000000..617f52f43e --- /dev/null +++ b/lib/cretonne/src/isa/arm32/mod.rs @@ -0,0 +1,73 @@ +//! ARM 32-bit Instruction Set Architecture. + +pub mod settings; +mod enc_tables; +mod registers; + +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, RegInfo, Encoding, Legalize}; +use ir::{InstructionData, DataFlowGraph}; + +#[allow(dead_code)] +struct Isa { + shared_flags: shared_settings::Flags, + isa_flags: settings::Flags, + cpumode: &'static [shared_enc_tables::Level1Entry], +} + +/// Get an ISA builder for creating ARM32 targets. +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 { + let level1 = if shared_flags.is_compressed() { + &enc_tables::LEVEL1_T32[..] + } else { + &enc_tables::LEVEL1_A32[..] + }; + 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 { + "arm32" + } + + fn flags(&self) -> &shared_settings::Flags { + &self.shared_flags + } + + fn register_info(&self) -> &RegInfo { + ®isters::INFO + } + + fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Result { + 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)) + .ok_or(Legalize::Expand) + }) + } + + fn recipe_names(&self) -> &'static [&'static str] { + &enc_tables::RECIPE_NAMES[..] + } +} diff --git a/lib/cretonne/src/isa/arm32/registers.rs b/lib/cretonne/src/isa/arm32/registers.rs new file mode 100644 index 0000000000..30e7fd58cf --- /dev/null +++ b/lib/cretonne/src/isa/arm32/registers.rs @@ -0,0 +1,32 @@ +//! ARM32 register descriptions. + +use isa::registers::{RegBank, RegInfo}; + +include!(concat!(env!("OUT_DIR"), "/registers-arm32.rs")); + +#[cfg(test)] +mod tests { + use super::INFO; + use isa::RegUnit; + + #[test] + fn unit_encodings() { + assert_eq!(INFO.parse_regunit("s0"), Some(0)); + assert_eq!(INFO.parse_regunit("s31"), Some(31)); + assert_eq!(INFO.parse_regunit("s32"), Some(32)); + assert_eq!(INFO.parse_regunit("r0"), Some(64)); + assert_eq!(INFO.parse_regunit("r15"), Some(79)); + } + + #[test] + fn unit_names() { + fn uname(ru: RegUnit) -> String { + INFO.display_regunit(ru).to_string() + } + + assert_eq!(uname(0), "%s0"); + assert_eq!(uname(1), "%s1"); + assert_eq!(uname(31), "%s31"); + assert_eq!(uname(64), "%r0"); + } +} diff --git a/lib/cretonne/src/isa/arm32/settings.rs b/lib/cretonne/src/isa/arm32/settings.rs new file mode 100644 index 0000000000..e857716a64 --- /dev/null +++ b/lib/cretonne/src/isa/arm32/settings.rs @@ -0,0 +1,9 @@ +//! ARM32 Settings. + +use settings::{self, detail, Builder}; +use std::fmt; + +// Include code generated by `lib/cretonne/meta/gen_settings.py`. This file contains a public +// `Flags` struct with an impl for all of the settings defined in +// `lib/cretonne/meta/cretonne/settings.py`. +include!(concat!(env!("OUT_DIR"), "/settings-arm32.rs")); diff --git a/lib/cretonne/src/isa/arm64/enc_tables.rs b/lib/cretonne/src/isa/arm64/enc_tables.rs new file mode 100644 index 0000000000..dbe65c4e8f --- /dev/null +++ b/lib/cretonne/src/isa/arm64/enc_tables.rs @@ -0,0 +1,8 @@ +//! Encoding tables for ARM64 ISA. + +use ir::InstructionData; +use ir::instructions::InstructionFormat; +use ir::types; +use isa::enc_tables::{Level1Entry, Level2Entry}; + +include!(concat!(env!("OUT_DIR"), "/encoding-arm64.rs")); diff --git a/lib/cretonne/src/isa/arm64/mod.rs b/lib/cretonne/src/isa/arm64/mod.rs new file mode 100644 index 0000000000..a4367a878b --- /dev/null +++ b/lib/cretonne/src/isa/arm64/mod.rs @@ -0,0 +1,66 @@ +//! ARM 64-bit Instruction Set Architecture. + +pub mod settings; +mod enc_tables; +mod registers; + +use super::super::settings as shared_settings; +use isa::enc_tables::{lookup_enclist, general_encoding}; +use isa::Builder as IsaBuilder; +use isa::{TargetIsa, RegInfo, Encoding, Legalize}; +use ir::{InstructionData, DataFlowGraph}; + +#[allow(dead_code)] +struct Isa { + shared_flags: shared_settings::Flags, + isa_flags: settings::Flags, +} + +/// Get an ISA builder for creating ARM64 targets. +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 { + Box::new(Isa { + isa_flags: settings::Flags::new(&shared_flags, builder), + shared_flags: shared_flags, + }) +} + +impl TargetIsa for Isa { + fn name(&self) -> &'static str { + "arm64" + } + + fn flags(&self) -> &shared_settings::Flags { + &self.shared_flags + } + + fn register_info(&self) -> &RegInfo { + ®isters::INFO + } + + fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Result { + lookup_enclist(inst.first_type(), + inst.opcode(), + &enc_tables::LEVEL1_A64[..], + &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)) + .ok_or(Legalize::Expand) + }) + } + + fn recipe_names(&self) -> &'static [&'static str] { + &enc_tables::RECIPE_NAMES[..] + } +} diff --git a/lib/cretonne/src/isa/arm64/registers.rs b/lib/cretonne/src/isa/arm64/registers.rs new file mode 100644 index 0000000000..2420db6df1 --- /dev/null +++ b/lib/cretonne/src/isa/arm64/registers.rs @@ -0,0 +1,37 @@ +//! ARM64 register descriptions. + +use isa::registers::{RegBank, RegInfo}; + +include!(concat!(env!("OUT_DIR"), "/registers-arm64.rs")); + +#[cfg(test)] +mod tests { + use super::INFO; + use isa::RegUnit; + + #[test] + fn unit_encodings() { + assert_eq!(INFO.parse_regunit("x0"), Some(0)); + assert_eq!(INFO.parse_regunit("x31"), Some(31)); + assert_eq!(INFO.parse_regunit("v0"), Some(32)); + assert_eq!(INFO.parse_regunit("v31"), Some(63)); + + assert_eq!(INFO.parse_regunit("x32"), None); + assert_eq!(INFO.parse_regunit("v32"), None); + } + + #[test] + fn unit_names() { + fn uname(ru: RegUnit) -> String { + INFO.display_regunit(ru).to_string() + } + + assert_eq!(uname(0), "%x0"); + assert_eq!(uname(1), "%x1"); + assert_eq!(uname(31), "%x31"); + assert_eq!(uname(32), "%v0"); + assert_eq!(uname(33), "%v1"); + assert_eq!(uname(63), "%v31"); + assert_eq!(uname(64), "%INVALID64"); + } +} diff --git a/lib/cretonne/src/isa/arm64/settings.rs b/lib/cretonne/src/isa/arm64/settings.rs new file mode 100644 index 0000000000..6427d7be99 --- /dev/null +++ b/lib/cretonne/src/isa/arm64/settings.rs @@ -0,0 +1,9 @@ +//! ARM64 Settings. + +use settings::{self, detail, Builder}; +use std::fmt; + +// Include code generated by `lib/cretonne/meta/gen_settings.py`. This file contains a public +// `Flags` struct with an impl for all of the settings defined in +// `lib/cretonne/meta/cretonne/settings.py`. +include!(concat!(env!("OUT_DIR"), "/settings-arm64.rs")); diff --git a/lib/cretonne/src/isa/intel/enc_tables.rs b/lib/cretonne/src/isa/intel/enc_tables.rs new file mode 100644 index 0000000000..842629b058 --- /dev/null +++ b/lib/cretonne/src/isa/intel/enc_tables.rs @@ -0,0 +1,8 @@ +//! Encoding tables for Intel ISAs. + +use ir::InstructionData; +use ir::instructions::InstructionFormat; +use ir::types; +use isa::enc_tables::{Level1Entry, Level2Entry}; + +include!(concat!(env!("OUT_DIR"), "/encoding-intel.rs")); diff --git a/lib/cretonne/src/isa/intel/mod.rs b/lib/cretonne/src/isa/intel/mod.rs new file mode 100644 index 0000000000..acad76743b --- /dev/null +++ b/lib/cretonne/src/isa/intel/mod.rs @@ -0,0 +1,73 @@ +//! Intel Instruction Set Architectures. + +pub mod settings; +mod enc_tables; +mod registers; + +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, RegInfo, Encoding, Legalize}; +use ir::{InstructionData, DataFlowGraph}; + +#[allow(dead_code)] +struct Isa { + shared_flags: shared_settings::Flags, + isa_flags: settings::Flags, + cpumode: &'static [shared_enc_tables::Level1Entry], +} + +/// Get an ISA builder for creating Intel targets. +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 { + let level1 = if shared_flags.is_64bit() { + &enc_tables::LEVEL1_I64[..] + } else { + &enc_tables::LEVEL1_I32[..] + }; + 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 { + "intel" + } + + fn flags(&self) -> &shared_settings::Flags { + &self.shared_flags + } + + fn register_info(&self) -> &RegInfo { + ®isters::INFO + } + + fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Result { + 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)) + .ok_or(Legalize::Expand) + }) + } + + fn recipe_names(&self) -> &'static [&'static str] { + &enc_tables::RECIPE_NAMES[..] + } +} diff --git a/lib/cretonne/src/isa/intel/registers.rs b/lib/cretonne/src/isa/intel/registers.rs new file mode 100644 index 0000000000..1946d0fc57 --- /dev/null +++ b/lib/cretonne/src/isa/intel/registers.rs @@ -0,0 +1,49 @@ +//! Intel register descriptions. + +use isa::registers::{RegBank, RegInfo}; + +include!(concat!(env!("OUT_DIR"), "/registers-intel.rs")); + +#[cfg(test)] +mod tests { + use super::INFO; + use isa::RegUnit; + + #[test] + fn unit_encodings() { + // The encoding of integer registers is not alphabetical. + assert_eq!(INFO.parse_regunit("rax"), Some(0)); + assert_eq!(INFO.parse_regunit("rbx"), Some(3)); + assert_eq!(INFO.parse_regunit("rcx"), Some(1)); + assert_eq!(INFO.parse_regunit("rdx"), Some(2)); + assert_eq!(INFO.parse_regunit("rsi"), Some(6)); + assert_eq!(INFO.parse_regunit("rdi"), Some(7)); + assert_eq!(INFO.parse_regunit("rbp"), Some(5)); + assert_eq!(INFO.parse_regunit("rsp"), Some(4)); + assert_eq!(INFO.parse_regunit("r8"), Some(8)); + assert_eq!(INFO.parse_regunit("r15"), Some(15)); + + assert_eq!(INFO.parse_regunit("xmm0"), Some(16)); + assert_eq!(INFO.parse_regunit("xmm15"), Some(31)); + } + + #[test] + fn unit_names() { + fn uname(ru: RegUnit) -> String { + INFO.display_regunit(ru).to_string() + } + + assert_eq!(uname(0), "%rax"); + assert_eq!(uname(3), "%rbx"); + assert_eq!(uname(1), "%rcx"); + assert_eq!(uname(2), "%rdx"); + assert_eq!(uname(6), "%rsi"); + assert_eq!(uname(7), "%rdi"); + assert_eq!(uname(5), "%rbp"); + assert_eq!(uname(4), "%rsp"); + assert_eq!(uname(8), "%r8"); + assert_eq!(uname(15), "%r15"); + assert_eq!(uname(16), "%xmm0"); + assert_eq!(uname(31), "%xmm15"); + } +} diff --git a/lib/cretonne/src/isa/intel/settings.rs b/lib/cretonne/src/isa/intel/settings.rs new file mode 100644 index 0000000000..341eb2dcc9 --- /dev/null +++ b/lib/cretonne/src/isa/intel/settings.rs @@ -0,0 +1,9 @@ +//! Intel Settings. + +use settings::{self, detail, Builder}; +use std::fmt; + +// Include code generated by `lib/cretonne/meta/gen_settings.py`. This file contains a public +// `Flags` struct with an impl for all of the settings defined in +// `lib/cretonne/meta/cretonne/settings.py`. +include!(concat!(env!("OUT_DIR"), "/settings-intel.rs")); diff --git a/lib/cretonne/src/isa/mod.rs b/lib/cretonne/src/isa/mod.rs index b1b3a8a8df..dc66355904 100644 --- a/lib/cretonne/src/isa/mod.rs +++ b/lib/cretonne/src/isa/mod.rs @@ -46,6 +46,9 @@ use settings; use ir::{InstructionData, DataFlowGraph}; pub mod riscv; +pub mod intel; +pub mod arm32; +pub mod arm64; mod encoding; mod enc_tables; mod registers; @@ -55,6 +58,9 @@ mod registers; pub fn lookup(name: &str) -> Option { match name { "riscv" => riscv_builder(), + "intel" => intel_builder(), + "arm32" => arm32_builder(), + "arm64" => arm64_builder(), _ => None, } } @@ -64,6 +70,18 @@ fn riscv_builder() -> Option { Some(riscv::isa_builder()) } +fn intel_builder() -> Option { + Some(intel::isa_builder()) +} + +fn arm32_builder() -> Option { + Some(arm32::isa_builder()) +} + +fn arm64_builder() -> Option { + Some(arm64::isa_builder()) +} + /// Builder for a `TargetIsa`. /// Modify the ISA-specific settings before creating the `TargetIsa` trait object with `finish`. pub struct Builder { diff --git a/lib/cretonne/src/settings.rs b/lib/cretonne/src/settings.rs index 291211b1b3..30ecff68e4 100644 --- a/lib/cretonne/src/settings.rs +++ b/lib/cretonne/src/settings.rs @@ -270,6 +270,7 @@ mod tests { "[shared]\n\ opt_level = \"default\"\n\ is_64bit = false\n\ + is_compressed = false\n\ enable_float = true\n\ enable_simd = true\n\ enable_atomics = true\n");