Path: blob/main/cranelift/assembler-x64/src/imm.rs
1692 views
//! Immediate operands to instructions.12use crate::api::CodeSink;3use std::fmt;45/// This helper function prints the unsigned hexadecimal representation of the6/// immediate value: e.g., this prints `$0xfe` to represent both the signed `-2`7/// and the unsigned `254`.8macro_rules! hexify {9($n:expr) => {10format!("$0x{:x}", $n)11};12}1314/// Like `hexify!`, but this performs a sign extension.15macro_rules! hexify_sign_extend {16($n:expr, $from:ty => $to:ty) => {{17let from: $from = $n; // Assert the type we expect.18let to = <$to>::from(from);19format!("$0x{:x}", to)20}};21}2223/// An 8-bit immediate operand.24#[derive(Clone, Copy, Debug)]25#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]26pub struct Imm8(u8);2728impl Imm8 {29#[must_use]30pub fn new(value: u8) -> Self {31Self(value)32}3334#[must_use]35pub fn value(&self) -> u8 {36self.037}3839pub fn encode(&self, sink: &mut impl CodeSink) {40sink.put1(self.0);41}42}4344impl From<u8> for Imm8 {45fn from(imm8: u8) -> Self {46Self(imm8)47}48}4950impl TryFrom<i32> for Imm8 {51type Error = std::num::TryFromIntError;52fn try_from(simm32: i32) -> Result<Self, Self::Error> {53Ok(Self(u8::try_from(simm32)?))54}55}5657impl fmt::Display for Imm8 {58fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {59write!(f, "$0x{:x}", self.0)60}61}6263/// A _signed_ 8-bit immediate operand (suitable for sign extension).64#[derive(Clone, Copy, Debug)]65#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]66pub struct Simm8(i8);6768impl Simm8 {69#[must_use]70pub fn new(value: i8) -> Self {71Self(value)72}7374#[must_use]75pub fn value(&self) -> i8 {76self.077}7879pub fn encode(&self, sink: &mut impl CodeSink) {80sink.put1(self.0 as u8);81}8283#[must_use]84pub fn to_string(&self, extend: Extension) -> String {85use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};86match extend {87None => hexify!(self.0),88SignExtendWord => hexify_sign_extend!(self.0, i8 => i16),89SignExtendLong => hexify_sign_extend!(self.0, i8 => i32),90SignExtendQuad => hexify_sign_extend!(self.0, i8 => i64),91}92}93}9495impl From<i8> for Simm8 {96fn from(simm8: i8) -> Self {97Self(simm8)98}99}100101impl TryFrom<i32> for Simm8 {102type Error = std::num::TryFromIntError;103fn try_from(simm32: i32) -> Result<Self, Self::Error> {104Ok(Self(i8::try_from(simm32)?))105}106}107108/// A 16-bit immediate operand.109#[derive(Copy, Clone, Debug)]110#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]111pub struct Imm16(u16);112113impl Imm16 {114#[must_use]115pub fn new(value: u16) -> Self {116Self(value)117}118119#[must_use]120pub fn value(&self) -> u16 {121self.0122}123124pub fn encode(&self, sink: &mut impl CodeSink) {125sink.put2(self.0);126}127}128129impl From<u16> for Imm16 {130fn from(imm16: u16) -> Self {131Self(imm16)132}133}134135impl TryFrom<i32> for Imm16 {136type Error = std::num::TryFromIntError;137fn try_from(simm32: i32) -> Result<Self, Self::Error> {138Ok(Self(u16::try_from(simm32)?))139}140}141142impl fmt::Display for Imm16 {143fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {144write!(f, "$0x{:x}", self.0)145}146}147148/// A _signed_ 16-bit immediate operand (suitable for sign extension).149#[derive(Copy, Clone, Debug)]150#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]151pub struct Simm16(i16);152153impl Simm16 {154#[must_use]155pub fn new(value: i16) -> Self {156Self(value)157}158159#[must_use]160pub fn value(&self) -> i16 {161self.0162}163164pub fn encode(&self, sink: &mut impl CodeSink) {165sink.put2(self.0 as u16);166}167168#[must_use]169pub fn to_string(&self, extend: Extension) -> String {170use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};171match extend {172None => hexify!(self.0),173SignExtendWord => unreachable!("the 16-bit value is already 16 bits"),174SignExtendLong => hexify_sign_extend!(self.0, i16 => i32),175SignExtendQuad => hexify_sign_extend!(self.0, i16 => i64),176}177}178}179180impl From<i16> for Simm16 {181fn from(simm16: i16) -> Self {182Self(simm16)183}184}185186impl TryFrom<i32> for Simm16 {187type Error = std::num::TryFromIntError;188fn try_from(simm32: i32) -> Result<Self, Self::Error> {189Ok(Self(i16::try_from(simm32)?))190}191}192193/// A 32-bit immediate operand.194///195/// Note that, "in 64-bit mode, the typical size of immediate operands remains196/// 32 bits. When the operand size is 64 bits, the processor sign-extends all197/// immediates to 64 bits prior to their use" (Intel SDM Vol. 2, 2.2.1.5).198#[derive(Copy, Clone, Debug)]199#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]200pub struct Imm32(u32);201202impl Imm32 {203#[must_use]204pub fn new(value: u32) -> Self {205Self(value)206}207208#[must_use]209pub fn value(&self) -> u32 {210self.0211}212213pub fn encode(&self, sink: &mut impl CodeSink) {214sink.put4(self.0);215}216}217218impl From<u32> for Imm32 {219fn from(imm32: u32) -> Self {220Self(imm32)221}222}223224impl From<i32> for Imm32 {225fn from(simm32: i32) -> Self {226// TODO: should this be a `TryFrom`?227Self(simm32 as u32)228}229}230231impl fmt::Display for Imm32 {232fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {233write!(f, "$0x{:x}", self.0)234}235}236237/// A _signed_ 32-bit immediate operand (suitable for sign extension).238///239/// Note that, "in 64-bit mode, the typical size of immediate operands remains240/// 32 bits. When the operand size is 64 bits, the processor sign-extends all241/// immediates to 64 bits prior to their use" (Intel SDM Vol. 2, 2.2.1.5).242#[derive(Copy, Clone, Debug)]243#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]244pub struct Simm32(i32);245246impl Simm32 {247#[must_use]248pub fn new(value: i32) -> Self {249Self(value)250}251252#[must_use]253pub fn value(&self) -> i32 {254self.0255}256257pub fn encode(&self, sink: &mut impl CodeSink) {258sink.put4(self.0 as u32);259}260261#[must_use]262pub fn to_string(&self, extend: Extension) -> String {263use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord};264match extend {265None => hexify!(self.0),266SignExtendWord => unreachable!("cannot sign extend a 32-bit value to 16 bits"),267SignExtendLong => unreachable!("the 32-bit value is already 32 bits"),268SignExtendQuad => hexify_sign_extend!(self.0, i32 => i64),269}270}271}272273impl From<i32> for Simm32 {274fn from(simm32: i32) -> Self {275Self(simm32)276}277}278279/// A 64-bit immediate operand.280///281/// This form is quite rare; see certain `mov` instructions.282#[derive(Copy, Clone, Debug)]283#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]284pub struct Imm64(u64);285286impl Imm64 {287#[must_use]288pub fn new(value: u64) -> Self {289Self(value)290}291292#[must_use]293pub fn value(&self) -> u64 {294self.0295}296297pub fn encode(&self, sink: &mut impl CodeSink) {298sink.put8(self.0);299}300}301302impl From<u64> for Imm64 {303fn from(imm64: u64) -> Self {304Self(imm64)305}306}307308impl fmt::Display for Imm64 {309fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {310write!(f, "$0x{:x}", self.0)311}312}313314/// Define the ways an immediate may be sign- or zero-extended.315#[derive(Clone, Copy, Debug)]316pub enum Extension {317None,318SignExtendQuad,319SignExtendLong,320SignExtendWord,321}322323324