Path: blob/main/cranelift/codegen/src/isa/riscv64/inst/imms.rs
1693 views
//! Riscv64 ISA definitions: immediate constants.12// Some variants are never constructed, but we still want them as options in the future.3use super::Inst;4use std::fmt::{Debug, Display, Formatter, Result};56#[derive(Copy, Clone, Debug, Default)]7pub struct Imm12 {8/// 16-bit container where the low 12 bits are the data payload.9///10/// Acquiring the underlying value requires sign-extending the 12th bit.11bits: u16,12}1314impl Imm12 {15pub(crate) const ZERO: Self = Self { bits: 0 };16pub(crate) const ONE: Self = Self { bits: 1 };1718pub fn maybe_from_u64(val: u64) -> Option<Imm12> {19Self::maybe_from_i64(val as i64)20}2122pub fn maybe_from_i64(val: i64) -> Option<Imm12> {23if val >= -2048 && val <= 2047 {24Some(Imm12 {25bits: val as u16 & 0xfff,26})27} else {28None29}30}3132#[inline]33pub fn from_i16(bits: i16) -> Self {34assert!(bits >= -2048 && bits <= 2047);35Self {36bits: (bits & 0xfff) as u16,37}38}3940#[inline]41pub fn as_i16(self) -> i16 {42(self.bits << 4) as i16 >> 443}4445#[inline]46pub fn bits(&self) -> u32 {47self.bits.into()48}49}5051impl From<Imm12> for i64 {52fn from(imm12: Imm12) -> i64 {53imm12.as_i16().into()54}55}5657impl Display for Imm12 {58fn fmt(&self, f: &mut Formatter<'_>) -> Result {59write!(f, "{:+}", self.as_i16())60}61}6263// signed64#[derive(Clone, Copy, Default)]65pub struct Imm20 {66/// 32-bit container where the low 20 bits are the data payload.67///68/// Acquiring the underlying value requires sign-extending the 20th bit.69bits: u32,70}7172impl Imm20 {73pub(crate) const ZERO: Self = Self { bits: 0 };7475pub fn maybe_from_u64(val: u64) -> Option<Imm20> {76Self::maybe_from_i64(val as i64)77}7879pub fn maybe_from_i64(val: i64) -> Option<Imm20> {80if val >= -(0x7_ffff + 1) && val <= 0x7_ffff {81Some(Imm20 { bits: val as u32 })82} else {83None84}85}8687#[inline]88pub fn from_i32(bits: i32) -> Self {89assert!(bits >= -(0x7_ffff + 1) && bits <= 0x7_ffff);90Self {91bits: (bits as u32) & 0xf_ffff,92}93}9495#[inline]96pub fn as_i32(&self) -> i32 {97((self.bits << 12) as i32) >> 1298}99100#[inline]101pub fn bits(&self) -> u32 {102self.bits103}104}105106impl Debug for Imm20 {107fn fmt(&self, f: &mut Formatter<'_>) -> Result {108write!(f, "{}", self.as_i32())109}110}111112impl Display for Imm20 {113fn fmt(&self, f: &mut Formatter<'_>) -> Result {114write!(f, "{}", self.bits)115}116}117118/// An unsigned 5-bit immediate.119#[derive(Clone, Copy, Debug, PartialEq)]120pub struct UImm5 {121value: u8,122}123124impl UImm5 {125/// Create an unsigned 5-bit immediate from u8.126pub fn maybe_from_u8(value: u8) -> Option<UImm5> {127if value < 32 {128Some(UImm5 { value })129} else {130None131}132}133134/// Bits for encoding.135pub fn bits(&self) -> u32 {136u32::from(self.value)137}138}139140impl Display for UImm5 {141fn fmt(&self, f: &mut Formatter<'_>) -> Result {142write!(f, "{}", self.value)143}144}145146/// A Signed 5-bit immediate.147#[derive(Clone, Copy, Debug, PartialEq)]148pub struct Imm5 {149value: i8,150}151152impl Imm5 {153/// Create an signed 5-bit immediate from an i8.154pub fn maybe_from_i8(value: i8) -> Option<Imm5> {155if value >= -16 && value <= 15 {156Some(Imm5 { value })157} else {158None159}160}161162pub fn from_bits(value: u8) -> Imm5 {163assert_eq!(value & 0x1f, value);164let signed = ((value << 3) as i8) >> 3;165Imm5 { value: signed }166}167168/// Bits for encoding.169pub fn bits(&self) -> u8 {170self.value as u8 & 0x1f171}172}173174impl Display for Imm5 {175fn fmt(&self, f: &mut Formatter<'_>) -> Result {176write!(f, "{}", self.value)177}178}179180/// A Signed 6-bit immediate.181#[derive(Clone, Copy, Debug, PartialEq)]182pub struct Imm6 {183value: i8,184}185186impl Imm6 {187/// Create an signed 6-bit immediate from an i16188pub fn maybe_from_i16(value: i16) -> Option<Self> {189if value >= -32 && value <= 31 {190Some(Self { value: value as i8 })191} else {192None193}194}195196pub fn maybe_from_i32(value: i32) -> Option<Self> {197value.try_into().ok().and_then(Imm6::maybe_from_i16)198}199200pub fn maybe_from_imm12(value: Imm12) -> Option<Self> {201Imm6::maybe_from_i16(value.as_i16())202}203204/// Bits for encoding.205pub fn bits(&self) -> u8 {206self.value as u8 & 0x3f207}208}209210impl Display for Imm6 {211fn fmt(&self, f: &mut Formatter<'_>) -> Result {212write!(f, "{}", self.value)213}214}215216/// A unsigned 6-bit immediate.217#[derive(Clone, Copy, Debug, PartialEq)]218pub struct Uimm6 {219value: u8,220}221222impl Uimm6 {223/// Create an unsigned 6-bit immediate from an u8224pub fn maybe_from_u8(value: u8) -> Option<Self> {225if value <= 63 {226Some(Self { value })227} else {228None229}230}231232/// Bits for encoding.233pub fn bits(&self) -> u8 {234self.value & 0x3f235}236}237238impl Display for Uimm6 {239fn fmt(&self, f: &mut Formatter<'_>) -> Result {240write!(f, "{}", self.value)241}242}243244/// A unsigned 5-bit immediate.245#[derive(Clone, Copy, Debug, PartialEq)]246pub struct Uimm5 {247value: u8,248}249250impl Uimm5 {251/// Create an unsigned 5-bit immediate from an u8252pub fn maybe_from_u8(value: u8) -> Option<Self> {253if value <= 31 {254Some(Self { value })255} else {256None257}258}259260/// Bits for encoding.261pub fn bits(&self) -> u8 {262self.value & 0x1f263}264}265266impl Display for Uimm5 {267fn fmt(&self, f: &mut Formatter<'_>) -> Result {268write!(f, "{}", self.value)269}270}271272/// A unsigned 2-bit immediate.273#[derive(Clone, Copy, Debug, PartialEq)]274pub struct Uimm2 {275value: u8,276}277278impl Uimm2 {279/// Create an unsigned 2-bit immediate from an u8280pub fn maybe_from_u8(value: u8) -> Option<Self> {281if value <= 3 {282Some(Self { value })283} else {284None285}286}287288/// Bits for encoding.289pub fn bits(&self) -> u8 {290self.value & 0x3291}292}293294impl Display for Uimm2 {295fn fmt(&self, f: &mut Formatter<'_>) -> Result {296write!(f, "{}", self.value)297}298}299300impl Inst {301pub(crate) fn imm_min() -> i64 {302let imm20_max: i64 = (1 << 19) << 12;303let imm12_max = 1 << 11;304-imm20_max - imm12_max305}306pub(crate) fn imm_max() -> i64 {307let imm20_max: i64 = ((1 << 19) - 1) << 12;308let imm12_max = (1 << 11) - 1;309imm20_max + imm12_max310}311312/// An imm20 immediate and an Imm12 immediate can generate a 32-bit immediate.313/// This helper produces an imm12, imm20, or both to generate the value.314///315/// `value` must be between `imm_min()` and `imm_max()`, or else316/// this helper returns `None`.317pub(crate) fn generate_imm(value: u64) -> Option<(Imm20, Imm12)> {318if let Some(imm12) = Imm12::maybe_from_u64(value) {319// can be load using single imm12.320return Some((Imm20::ZERO, imm12));321}322let value = value as i64;323if !(value >= Self::imm_min() && value <= Self::imm_max()) {324// not in range, return None.325return None;326}327const MOD_NUM: i64 = 4096;328let (imm20, imm12) = if value > 0 {329let mut imm20 = value / MOD_NUM;330let mut imm12 = value % MOD_NUM;331if imm12 >= 2048 {332imm12 -= MOD_NUM;333imm20 += 1;334}335assert!(imm12 >= -2048 && imm12 <= 2047);336(imm20, imm12)337} else {338// this is the abs value.339let value_abs = value.abs();340let imm20 = value_abs / MOD_NUM;341let imm12 = value_abs % MOD_NUM;342let mut imm20 = -imm20;343let mut imm12 = -imm12;344if imm12 < -2048 {345imm12 += MOD_NUM;346imm20 -= 1;347}348(imm20, imm12)349};350assert!(imm20 != 0 || imm12 != 0);351let imm20 = i32::try_from(imm20).unwrap();352let imm12 = i16::try_from(imm12).unwrap();353Some((Imm20::from_i32(imm20), Imm12::from_i16(imm12)))354}355}356357#[cfg(test)]358mod test {359use super::*;360#[test]361fn test_imm12() {362let x = Imm12::ZERO;363assert_eq!(0, x.bits());364Imm12::maybe_from_u64(0xffff_ffff_ffff_ffff).unwrap();365}366367#[test]368fn imm20_and_imm12() {369assert!(Inst::imm_max() == (i32::MAX - 2048) as i64);370assert!(Inst::imm_min() == i32::MIN as i64 - 2048);371}372}373374375