Path: blob/main/cranelift/assembler-x64/src/imm.rs
3068 views
//! Immediate operands to instructions.12use crate::api::CodeSink;3use alloc::{format, string::String};4use core::fmt;56/// This helper function prints the unsigned hexadecimal representation of the7/// immediate value: e.g., this prints `$0xfe` to represent both the signed `-2`8/// and the unsigned `254`.9macro_rules! hexify {10($n:expr) => {11format!("$0x{:x}", $n)12};13}1415/// Like `hexify!`, but this performs a sign extension.16macro_rules! hexify_sign_extend {17($n:expr, $from:ty => $to:ty) => {{18let from: $from = $n; // Assert the type we expect.19let to = <$to>::from(from);20format!("$0x{:x}", to)21}};22}2324/// An 8-bit immediate operand.25#[derive(Clone, Copy, Debug)]26#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]27pub struct Imm8(u8);2829impl Imm8 {30#[must_use]31pub fn new(value: u8) -> Self {32Self(value)33}3435#[must_use]36pub fn value(&self) -> u8 {37self.038}3940pub fn encode(&self, sink: &mut impl CodeSink) {41sink.put1(self.0);42}43}4445impl From<u8> for Imm8 {46fn from(imm8: u8) -> Self {47Self(imm8)48}49}5051impl TryFrom<i32> for Imm8 {52type Error = core::num::TryFromIntError;53fn try_from(simm32: i32) -> Result<Self, Self::Error> {54Ok(Self(u8::try_from(simm32)?))55}56}5758impl fmt::Display for Imm8 {59fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {60write!(f, "$0x{:x}", self.0)61}62}6364/// A _signed_ 8-bit immediate operand (suitable for sign extension).65#[derive(Clone, Copy, Debug)]66#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]67pub struct Simm8(i8);6869impl Simm8 {70#[must_use]71pub fn new(value: i8) -> Self {72Self(value)73}7475#[must_use]76pub fn value(&self) -> i8 {77self.078}7980pub fn encode(&self, sink: &mut impl CodeSink) {81sink.put1(self.0 as u8);82}8384#[must_use]85pub fn to_string(&self, extend: Extension) -> String {86use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};87match extend {88None => hexify!(self.0),89SignExtendWord => hexify_sign_extend!(self.0, i8 => i16),90SignExtendLong => hexify_sign_extend!(self.0, i8 => i32),91SignExtendQuad => hexify_sign_extend!(self.0, i8 => i64),92}93}94}9596impl From<i8> for Simm8 {97fn from(simm8: i8) -> Self {98Self(simm8)99}100}101102impl TryFrom<i32> for Simm8 {103type Error = core::num::TryFromIntError;104fn try_from(simm32: i32) -> Result<Self, Self::Error> {105Ok(Self(i8::try_from(simm32)?))106}107}108109/// A 16-bit immediate operand.110#[derive(Copy, Clone, Debug)]111#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]112pub struct Imm16(u16);113114impl Imm16 {115#[must_use]116pub fn new(value: u16) -> Self {117Self(value)118}119120#[must_use]121pub fn value(&self) -> u16 {122self.0123}124125pub fn encode(&self, sink: &mut impl CodeSink) {126sink.put2(self.0);127}128}129130impl From<u16> for Imm16 {131fn from(imm16: u16) -> Self {132Self(imm16)133}134}135136impl TryFrom<i32> for Imm16 {137type Error = core::num::TryFromIntError;138fn try_from(simm32: i32) -> Result<Self, Self::Error> {139Ok(Self(u16::try_from(simm32)?))140}141}142143impl fmt::Display for Imm16 {144fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {145write!(f, "$0x{:x}", self.0)146}147}148149/// A _signed_ 16-bit immediate operand (suitable for sign extension).150#[derive(Copy, Clone, Debug)]151#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]152pub struct Simm16(i16);153154impl Simm16 {155#[must_use]156pub fn new(value: i16) -> Self {157Self(value)158}159160#[must_use]161pub fn value(&self) -> i16 {162self.0163}164165pub fn encode(&self, sink: &mut impl CodeSink) {166sink.put2(self.0 as u16);167}168169#[must_use]170pub fn to_string(&self, extend: Extension) -> String {171use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};172match extend {173None => hexify!(self.0),174SignExtendWord => unreachable!("the 16-bit value is already 16 bits"),175SignExtendLong => hexify_sign_extend!(self.0, i16 => i32),176SignExtendQuad => hexify_sign_extend!(self.0, i16 => i64),177}178}179}180181impl From<i16> for Simm16 {182fn from(simm16: i16) -> Self {183Self(simm16)184}185}186187impl TryFrom<i32> for Simm16 {188type Error = core::num::TryFromIntError;189fn try_from(simm32: i32) -> Result<Self, Self::Error> {190Ok(Self(i16::try_from(simm32)?))191}192}193194/// A 32-bit immediate operand.195///196/// Note that, "in 64-bit mode, the typical size of immediate operands remains197/// 32 bits. When the operand size is 64 bits, the processor sign-extends all198/// immediates to 64 bits prior to their use" (Intel SDM Vol. 2, 2.2.1.5).199#[derive(Copy, Clone, Debug)]200#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]201pub struct Imm32(u32);202203impl Imm32 {204#[must_use]205pub fn new(value: u32) -> Self {206Self(value)207}208209#[must_use]210pub fn value(&self) -> u32 {211self.0212}213214pub fn encode(&self, sink: &mut impl CodeSink) {215sink.put4(self.0);216}217}218219impl From<u32> for Imm32 {220fn from(imm32: u32) -> Self {221Self(imm32)222}223}224225impl From<i32> for Imm32 {226fn from(simm32: i32) -> Self {227// TODO: should this be a `TryFrom`?228Self(simm32 as u32)229}230}231232impl fmt::Display for Imm32 {233fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {234write!(f, "$0x{:x}", self.0)235}236}237238/// A _signed_ 32-bit immediate operand (suitable for sign extension).239///240/// Note that, "in 64-bit mode, the typical size of immediate operands remains241/// 32 bits. When the operand size is 64 bits, the processor sign-extends all242/// immediates to 64 bits prior to their use" (Intel SDM Vol. 2, 2.2.1.5).243#[derive(Copy, Clone, Debug)]244#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]245pub struct Simm32(i32);246247impl Simm32 {248#[must_use]249pub fn new(value: i32) -> Self {250Self(value)251}252253#[must_use]254pub fn value(&self) -> i32 {255self.0256}257258pub fn encode(&self, sink: &mut impl CodeSink) {259sink.put4(self.0 as u32);260}261262#[must_use]263pub fn to_string(&self, extend: Extension) -> String {264use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};265match extend {266None => hexify!(self.0),267SignExtendWord => unreachable!("cannot sign extend a 32-bit value to 16 bits"),268SignExtendLong => unreachable!("the 32-bit value is already 32 bits"),269SignExtendQuad => hexify_sign_extend!(self.0, i32 => i64),270}271}272}273274impl From<i32> for Simm32 {275fn from(simm32: i32) -> Self {276Self(simm32)277}278}279280/// A 64-bit immediate operand.281///282/// This form is quite rare; see certain `mov` instructions.283#[derive(Copy, Clone, Debug)]284#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]285pub struct Imm64(u64);286287impl Imm64 {288#[must_use]289pub fn new(value: u64) -> Self {290Self(value)291}292293#[must_use]294pub fn value(&self) -> u64 {295self.0296}297298pub fn encode(&self, sink: &mut impl CodeSink) {299sink.put8(self.0);300}301}302303impl From<u64> for Imm64 {304fn from(imm64: u64) -> Self {305Self(imm64)306}307}308309impl fmt::Display for Imm64 {310fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {311write!(f, "$0x{:x}", self.0)312}313}314315/// Define the ways an immediate may be sign- or zero-extended.316#[derive(Clone, Copy, Debug)]317pub enum Extension {318None,319SignExtendQuad,320SignExtendLong,321SignExtendWord,322}323324325