Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/cranelift-codegen-0.91.1/src/isa/x64/inst/args.rs
Line
Count
Source (jump to first uncovered line)
1
//! Instruction operand sub-components (aka "parts"): definitions and printing.
2
3
use super::regs::{self};
4
use super::EmitState;
5
use crate::ir::condcodes::{FloatCC, IntCC};
6
use crate::ir::{MemFlags, Type};
7
use crate::isa::x64::inst::regs::pretty_print_reg;
8
use crate::isa::x64::inst::Inst;
9
use crate::machinst::*;
10
use regalloc2::VReg;
11
use smallvec::{smallvec, SmallVec};
12
use std::fmt;
13
use std::string::String;
14
15
/// An extenstion trait for converting `Writable{Xmm,Gpr}` to `Writable<Reg>`.
16
pub trait ToWritableReg {
17
    fn to_writable_reg(&self) -> Writable<Reg>;
18
}
19
20
/// An extension trait for converting `Writable<Reg>` to `Writable{Xmm,Gpr}`.
21
pub trait FromWritableReg: Sized {
22
    fn from_writable_reg(w: Writable<Reg>) -> Option<Self>;
23
}
24
25
/// A macro for defining a newtype of `Reg` that enforces some invariant about
26
/// the wrapped `Reg` (such as that it is of a particular register class).
27
macro_rules! newtype_of_reg {
28
    (
29
        $newtype_reg:ident,
30
        $newtype_writable_reg:ident,
31
        $newtype_option_writable_reg:ident,
32
        $newtype_reg_mem:ident,
33
        $newtype_reg_mem_imm:ident,
34
        $newtype_imm8_reg:ident,
35
        |$check_reg:ident| $check:expr
36
    ) => {
37
        /// A newtype wrapper around `Reg`.
38
        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
39
        pub struct $newtype_reg(Reg);
40
41
        impl PartialEq<Reg> for $newtype_reg {
42
0
            fn eq(&self, other: &Reg) -> bool {
43
0
                self.0 == *other
44
0
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::Gpr as core::cmp::PartialEq<cranelift_codegen::machinst::reg::Reg>>::eq
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::Xmm as core::cmp::PartialEq<cranelift_codegen::machinst::reg::Reg>>::eq
45
        }
46
47
        impl From<$newtype_reg> for Reg {
48
413k
            fn from(r: $newtype_reg) -> Self {
49
413k
                r.0
50
413k
            }
<cranelift_codegen::machinst::reg::Reg as core::convert::From<cranelift_codegen::isa::x64::inst::args::Gpr>>::from
Line
Count
Source
48
235k
            fn from(r: $newtype_reg) -> Self {
49
235k
                r.0
50
235k
            }
<cranelift_codegen::machinst::reg::Reg as core::convert::From<cranelift_codegen::isa::x64::inst::args::Xmm>>::from
Line
Count
Source
48
177k
            fn from(r: $newtype_reg) -> Self {
49
177k
                r.0
50
177k
            }
51
        }
52
53
        impl $newtype_reg {
54
            /// Create this newtype from the given register, or return `None` if the register
55
            /// is not a valid instance of this newtype.
56
2.80M
            pub fn new($check_reg: Reg) -> Option<Self> {
57
                if $check {
58
2.80M
                    Some(Self($check_reg))
59
                } else {
60
0
                    None
61
                }
62
2.80M
            }
<cranelift_codegen::isa::x64::inst::args::Gpr>::new
Line
Count
Source
56
2.09M
            pub fn new($check_reg: Reg) -> Option<Self> {
57
                if $check {
58
2.09M
                    Some(Self($check_reg))
59
                } else {
60
0
                    None
61
                }
62
2.09M
            }
<cranelift_codegen::isa::x64::inst::args::Xmm>::new
Line
Count
Source
56
708k
            pub fn new($check_reg: Reg) -> Option<Self> {
57
                if $check {
58
708k
                    Some(Self($check_reg))
59
                } else {
60
0
                    None
61
                }
62
708k
            }
63
64
            /// Get this newtype's underlying `Reg`.
65
3.86M
            pub fn to_reg(self) -> Reg {
66
3.86M
                self.0
67
3.86M
            }
<cranelift_codegen::isa::x64::inst::args::Gpr>::to_reg
Line
Count
Source
65
2.71M
            pub fn to_reg(self) -> Reg {
66
2.71M
                self.0
67
2.71M
            }
<cranelift_codegen::isa::x64::inst::args::Xmm>::to_reg
Line
Count
Source
65
1.15M
            pub fn to_reg(self) -> Reg {
66
1.15M
                self.0
67
1.15M
            }
68
        }
69
70
        // Convenience impl so that people working with this newtype can use it
71
        // "just like" a plain `Reg`.
72
        //
73
        // NB: We cannot implement `DerefMut` because that would let people do
74
        // nasty stuff like `*my_gpr.deref_mut() = some_xmm_reg`, breaking the
75
        // invariants that `Gpr` provides.
76
        impl std::ops::Deref for $newtype_reg {
77
            type Target = Reg;
78
79
197k
            fn deref(&self) -> &Reg {
80
197k
                &self.0
81
197k
            }
<cranelift_codegen::isa::x64::inst::args::Gpr as core::ops::deref::Deref>::deref
Line
Count
Source
79
197k
            fn deref(&self) -> &Reg {
80
197k
                &self.0
81
197k
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::Xmm as core::ops::deref::Deref>::deref
82
        }
83
84
        pub type $newtype_writable_reg = Writable<$newtype_reg>;
85
86
        #[allow(dead_code)] // Used by some newtypes and not others.
87
        pub type $newtype_option_writable_reg = Option<Writable<$newtype_reg>>;
88
89
        impl ToWritableReg for $newtype_writable_reg {
90
794k
            fn to_writable_reg(&self) -> Writable<Reg> {
91
794k
                Writable::from_reg(self.to_reg().to_reg())
92
794k
            }
<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr> as cranelift_codegen::isa::x64::inst::args::ToWritableReg>::to_writable_reg
Line
Count
Source
90
499k
            fn to_writable_reg(&self) -> Writable<Reg> {
91
499k
                Writable::from_reg(self.to_reg().to_reg())
92
499k
            }
<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Xmm> as cranelift_codegen::isa::x64::inst::args::ToWritableReg>::to_writable_reg
Line
Count
Source
90
294k
            fn to_writable_reg(&self) -> Writable<Reg> {
91
294k
                Writable::from_reg(self.to_reg().to_reg())
92
294k
            }
93
        }
94
95
        impl FromWritableReg for $newtype_writable_reg {
96
996k
            fn from_writable_reg(w: Writable<Reg>) -> Option<Self> {
97
996k
                Some(Writable::from_reg($newtype_reg::new(w.to_reg())?))
98
996k
            }
<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Gpr> as cranelift_codegen::isa::x64::inst::args::FromWritableReg>::from_writable_reg
Line
Count
Source
96
805k
            fn from_writable_reg(w: Writable<Reg>) -> Option<Self> {
97
805k
                Some(Writable::from_reg($newtype_reg::new(w.to_reg())?))
98
805k
            }
<cranelift_codegen::machinst::reg::Writable<cranelift_codegen::isa::x64::inst::args::Xmm> as cranelift_codegen::isa::x64::inst::args::FromWritableReg>::from_writable_reg
Line
Count
Source
96
190k
            fn from_writable_reg(w: Writable<Reg>) -> Option<Self> {
97
190k
                Some(Writable::from_reg($newtype_reg::new(w.to_reg())?))
98
190k
            }
99
        }
100
101
        /// A newtype wrapper around `RegMem` for general-purpose registers.
102
        #[derive(Clone, Debug)]
103
        pub struct $newtype_reg_mem(RegMem);
104
105
        impl From<$newtype_reg_mem> for RegMem {
106
9.68k
            fn from(rm: $newtype_reg_mem) -> Self {
107
9.68k
                rm.0
108
9.68k
            }
<cranelift_codegen::isa::x64::inst::args::RegMem as core::convert::From<cranelift_codegen::isa::x64::inst::args::GprMem>>::from
Line
Count
Source
106
9.68k
            fn from(rm: $newtype_reg_mem) -> Self {
107
9.68k
                rm.0
108
9.68k
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::RegMem as core::convert::From<cranelift_codegen::isa::x64::inst::args::XmmMem>>::from
109
        }
110
111
        impl From<$newtype_reg> for $newtype_reg_mem {
112
71.0k
            fn from(r: $newtype_reg) -> Self {
113
71.0k
                $newtype_reg_mem(RegMem::reg(r.into()))
114
71.0k
            }
<cranelift_codegen::isa::x64::inst::args::XmmMem as core::convert::From<cranelift_codegen::isa::x64::inst::args::Xmm>>::from
Line
Count
Source
112
49.8k
            fn from(r: $newtype_reg) -> Self {
113
49.8k
                $newtype_reg_mem(RegMem::reg(r.into()))
114
49.8k
            }
<cranelift_codegen::isa::x64::inst::args::GprMem as core::convert::From<cranelift_codegen::isa::x64::inst::args::Gpr>>::from
Line
Count
Source
112
21.1k
            fn from(r: $newtype_reg) -> Self {
113
21.1k
                $newtype_reg_mem(RegMem::reg(r.into()))
114
21.1k
            }
115
        }
116
117
        impl $newtype_reg_mem {
118
            /// Construct a `RegMem` newtype from the given `RegMem`, or return
119
            /// `None` if the `RegMem` is not a valid instance of this `RegMem`
120
            /// newtype.
121
505k
            pub fn new(rm: RegMem) -> Option<Self> {
122
249k
                match rm {
123
255k
                    RegMem::Mem { addr: _ } => Some(Self(rm)),
124
249k
                    RegMem::Reg { reg: $check_reg } if $check => Some(Self(rm)),
125
0
                    RegMem::Reg { reg: _ } => None,
126
                }
127
505k
            }
<cranelift_codegen::isa::x64::inst::args::GprMem>::new
Line
Count
Source
121
200k
            pub fn new(rm: RegMem) -> Option<Self> {
122
121k
                match rm {
123
78.8k
                    RegMem::Mem { addr: _ } => Some(Self(rm)),
124
121k
                    RegMem::Reg { reg: $check_reg } if $check => Some(Self(rm)),
125
0
                    RegMem::Reg { reg: _ } => None,
126
                }
127
200k
            }
<cranelift_codegen::isa::x64::inst::args::XmmMem>::new
Line
Count
Source
121
304k
            pub fn new(rm: RegMem) -> Option<Self> {
122
127k
                match rm {
123
176k
                    RegMem::Mem { addr: _ } => Some(Self(rm)),
124
127k
                    RegMem::Reg { reg: $check_reg } if $check => Some(Self(rm)),
125
0
                    RegMem::Reg { reg: _ } => None,
126
                }
127
304k
            }
128
129
            /// Convert this newtype into its underlying `RegMem`.
130
794k
            pub fn to_reg_mem(self) -> RegMem {
131
794k
                self.0
132
794k
            }
<cranelift_codegen::isa::x64::inst::args::GprMem>::to_reg_mem
Line
Count
Source
130
212k
            pub fn to_reg_mem(self) -> RegMem {
131
212k
                self.0
132
212k
            }
<cranelift_codegen::isa::x64::inst::args::XmmMem>::to_reg_mem
Line
Count
Source
130
582k
            pub fn to_reg_mem(self) -> RegMem {
131
582k
                self.0
132
582k
            }
133
134
            #[allow(dead_code)] // Used by some newtypes and not others.
135
401k
            pub fn get_operands<F: Fn(VReg) -> VReg>(
136
401k
                &self,
137
401k
                collector: &mut OperandCollector<'_, F>,
138
401k
            ) {
139
401k
                self.0.get_operands(collector);
140
401k
            }
<cranelift_codegen::isa::x64::inst::args::GprMem>::get_operands::<<cranelift_codegen::machinst::vcode::VCodeBuilder<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>::collect_operands::{closure#0}>
Line
Count
Source
135
182k
            pub fn get_operands<F: Fn(VReg) -> VReg>(
136
182k
                &self,
137
182k
                collector: &mut OperandCollector<'_, F>,
138
182k
            ) {
139
182k
                self.0.get_operands(collector);
140
182k
            }
<cranelift_codegen::isa::x64::inst::args::XmmMem>::get_operands::<<cranelift_codegen::machinst::vcode::VCodeBuilder<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>::collect_operands::{closure#0}>
Line
Count
Source
135
219k
            pub fn get_operands<F: Fn(VReg) -> VReg>(
136
219k
                &self,
137
219k
                collector: &mut OperandCollector<'_, F>,
138
219k
            ) {
139
219k
                self.0.get_operands(collector);
140
219k
            }
141
        }
142
        impl PrettyPrint for $newtype_reg_mem {
143
0
            fn pretty_print(&self, size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
144
0
                self.0.pretty_print(size, allocs)
145
0
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::GprMem as cranelift_codegen::machinst::reg::PrettyPrint>::pretty_print
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::XmmMem as cranelift_codegen::machinst::reg::PrettyPrint>::pretty_print
146
        }
147
148
        /// A newtype wrapper around `RegMemImm`.
149
        #[derive(Clone, Debug)]
150
        pub struct $newtype_reg_mem_imm(RegMemImm);
151
152
        impl From<$newtype_reg_mem_imm> for RegMemImm {
153
0
            fn from(rmi: $newtype_reg_mem_imm) -> RegMemImm {
154
0
                rmi.0
155
0
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::RegMemImm as core::convert::From<cranelift_codegen::isa::x64::inst::args::GprMemImm>>::from
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::RegMemImm as core::convert::From<cranelift_codegen::isa::x64::inst::args::XmmMemImm>>::from
156
        }
157
158
        impl From<$newtype_reg> for $newtype_reg_mem_imm {
159
14.1k
            fn from(r: $newtype_reg) -> Self {
160
14.1k
                $newtype_reg_mem_imm(RegMemImm::reg(r.into()))
161
14.1k
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::XmmMemImm as core::convert::From<cranelift_codegen::isa::x64::inst::args::Xmm>>::from
<cranelift_codegen::isa::x64::inst::args::GprMemImm as core::convert::From<cranelift_codegen::isa::x64::inst::args::Gpr>>::from
Line
Count
Source
159
14.1k
            fn from(r: $newtype_reg) -> Self {
160
14.1k
                $newtype_reg_mem_imm(RegMemImm::reg(r.into()))
161
14.1k
            }
162
        }
163
164
        impl $newtype_reg_mem_imm {
165
            /// Construct this newtype from the given `RegMemImm`, or return
166
            /// `None` if the `RegMemImm` is not a valid instance of this
167
            /// newtype.
168
354k
            pub fn new(rmi: RegMemImm) -> Option<Self> {
169
205k
                match rmi {
170
143k
                    RegMemImm::Imm { .. } => Some(Self(rmi)),
171
6.54k
                    RegMemImm::Mem { addr: _ } => Some(Self(rmi)),
172
205k
                    RegMemImm::Reg { reg: $check_reg } if $check => Some(Self(rmi)),
173
0
                    RegMemImm::Reg { reg: _ } => None,
174
                }
175
354k
            }
<cranelift_codegen::isa::x64::inst::args::GprMemImm>::new
Line
Count
Source
168
354k
            pub fn new(rmi: RegMemImm) -> Option<Self> {
169
205k
                match rmi {
170
143k
                    RegMemImm::Imm { .. } => Some(Self(rmi)),
171
6.54k
                    RegMemImm::Mem { addr: _ } => Some(Self(rmi)),
172
205k
                    RegMemImm::Reg { reg: $check_reg } if $check => Some(Self(rmi)),
173
0
                    RegMemImm::Reg { reg: _ } => None,
174
                }
175
354k
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::XmmMemImm>::new
176
177
            /// Convert this newtype into its underlying `RegMemImm`.
178
            #[allow(dead_code)] // Used by some newtypes and not others.
179
511k
            pub fn to_reg_mem_imm(self) -> RegMemImm {
180
511k
                self.0
181
511k
            }
<cranelift_codegen::isa::x64::inst::args::GprMemImm>::to_reg_mem_imm
Line
Count
Source
179
511k
            pub fn to_reg_mem_imm(self) -> RegMemImm {
180
511k
                self.0
181
511k
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::XmmMemImm>::to_reg_mem_imm
182
183
            #[allow(dead_code)] // Used by some newtypes and not others.
184
55.8k
            pub fn get_operands<F: Fn(VReg) -> VReg>(
185
55.8k
                &self,
186
55.8k
                collector: &mut OperandCollector<'_, F>,
187
55.8k
            ) {
188
55.8k
                self.0.get_operands(collector);
189
55.8k
            }
<cranelift_codegen::isa::x64::inst::args::GprMemImm>::get_operands::<<cranelift_codegen::machinst::vcode::VCodeBuilder<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>::collect_operands::{closure#0}>
Line
Count
Source
184
55.8k
            pub fn get_operands<F: Fn(VReg) -> VReg>(
185
55.8k
                &self,
186
55.8k
                collector: &mut OperandCollector<'_, F>,
187
55.8k
            ) {
188
55.8k
                self.0.get_operands(collector);
189
55.8k
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::XmmMemImm>::get_operands::<<cranelift_codegen::machinst::vcode::VCodeBuilder<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>::collect_operands::{closure#0}>
190
        }
191
192
        impl PrettyPrint for $newtype_reg_mem_imm {
193
0
            fn pretty_print(&self, size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
194
0
                self.0.pretty_print(size, allocs)
195
0
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::GprMemImm as cranelift_codegen::machinst::reg::PrettyPrint>::pretty_print
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::XmmMemImm as cranelift_codegen::machinst::reg::PrettyPrint>::pretty_print
196
        }
197
198
        /// A newtype wrapper around `Imm8Reg`.
199
        #[derive(Clone, Debug)]
200
        #[allow(dead_code)] // Used by some newtypes and not others.
201
        pub struct $newtype_imm8_reg(Imm8Reg);
202
203
        impl From<$newtype_reg> for $newtype_imm8_reg {
204
862
            fn from(r: $newtype_reg) -> Self {
205
862
                Self(Imm8Reg::Reg { reg: r.to_reg() })
206
862
            }
<cranelift_codegen::isa::x64::inst::args::Imm8Gpr as core::convert::From<cranelift_codegen::isa::x64::inst::args::Gpr>>::from
Line
Count
Source
204
862
            fn from(r: $newtype_reg) -> Self {
205
862
                Self(Imm8Reg::Reg { reg: r.to_reg() })
206
862
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::Imm8Xmm as core::convert::From<cranelift_codegen::isa::x64::inst::args::Xmm>>::from
207
        }
208
209
        impl $newtype_imm8_reg {
210
            /// Construct this newtype from the given `Imm8Reg`, or return
211
            /// `None` if the `Imm8Reg` is not a valid instance of this newtype.
212
            #[allow(dead_code)] // Used by some newtypes and not others.
213
8.37k
            pub fn new(imm8_reg: Imm8Reg) -> Option<Self> {
214
0
                match imm8_reg {
215
8.37k
                    Imm8Reg::Imm8 { .. } => Some(Self(imm8_reg)),
216
0
                    Imm8Reg::Reg { reg: $check_reg } if $check => Some(Self(imm8_reg)),
217
0
                    Imm8Reg::Reg { reg: _ } => None,
218
                }
219
8.37k
            }
<cranelift_codegen::isa::x64::inst::args::Imm8Gpr>::new
Line
Count
Source
213
8.37k
            pub fn new(imm8_reg: Imm8Reg) -> Option<Self> {
214
0
                match imm8_reg {
215
8.37k
                    Imm8Reg::Imm8 { .. } => Some(Self(imm8_reg)),
216
0
                    Imm8Reg::Reg { reg: $check_reg } if $check => Some(Self(imm8_reg)),
217
0
                    Imm8Reg::Reg { reg: _ } => None,
218
                }
219
8.37k
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::Imm8Xmm>::new
220
221
            /// Convert this newtype into its underlying `Imm8Reg`.
222
            #[allow(dead_code)] // Used by some newtypes and not others.
223
18.4k
            pub fn to_imm8_reg(self) -> Imm8Reg {
224
18.4k
                self.0
225
18.4k
            }
<cranelift_codegen::isa::x64::inst::args::Imm8Gpr>::to_imm8_reg
Line
Count
Source
223
18.4k
            pub fn to_imm8_reg(self) -> Imm8Reg {
224
18.4k
                self.0
225
18.4k
            }
Unexecuted instantiation: <cranelift_codegen::isa::x64::inst::args::Imm8Xmm>::to_imm8_reg
226
        }
227
    };
228
}
229
230
// Define a newtype of `Reg` for general-purpose registers.
231
newtype_of_reg!(
232
    Gpr,
233
    WritableGpr,
234
    OptionWritableGpr,
235
    GprMem,
236
    GprMemImm,
237
    Imm8Gpr,
238
    |reg| reg.class() == RegClass::Int
239
);
240
241
// Define a newtype of `Reg` for XMM registers.
242
newtype_of_reg!(
243
    Xmm,
244
    WritableXmm,
245
    OptionWritableXmm,
246
    XmmMem,
247
    XmmMemImm,
248
    Imm8Xmm,
249
    |reg| reg.class() == RegClass::Float
250
);
251
252
// N.B.: `Amode` is defined in `inst.isle`. We add some convenience
253
// constructors here.
254
255
// Re-export the type from the ISLE generated code.
256
pub use crate::isa::x64::lower::isle::generated_code::Amode;
257
258
impl Amode {
259
96.4k
    pub(crate) fn imm_reg(simm32: u32, base: Reg) -> Self {
260
96.4k
        debug_assert!(base.class() == RegClass::Int);
261
96.4k
        Self::ImmReg {
262
96.4k
            simm32,
263
96.4k
            base,
264
96.4k
            flags: MemFlags::trusted(),
265
96.4k
        }
266
96.4k
    }
267
268
13.6k
    pub(crate) fn imm_reg_reg_shift(simm32: u32, base: Gpr, index: Gpr, shift: u8) -> Self {
269
13.6k
        debug_assert!(base.class() == RegClass::Int);
270
13.6k
        debug_assert!(index.class() == RegClass::Int);
271
13.6k
        debug_assert!(shift <= 3);
272
13.6k
        Self::ImmRegRegShift {
273
13.6k
            simm32,
274
13.6k
            base,
275
13.6k
            index,
276
13.6k
            shift,
277
13.6k
            flags: MemFlags::trusted(),
278
13.6k
        }
279
13.6k
    }
280
281
75.5k
    pub(crate) fn rip_relative(target: MachLabel) -> Self {
282
75.5k
        Self::RipRelative { target }
283
75.5k
    }
284
285
13.2k
    pub(crate) fn with_flags(&self, flags: MemFlags) -> Self {
286
13.2k
        match self {
287
288
            &Self::ImmReg { simm32, base, .. } => Self::ImmReg {
288
288
                simm32,
289
288
                base,
290
288
                flags,
291
288
            },
292
            &Self::ImmRegRegShift {
293
12.9k
                simm32,
294
12.9k
                base,
295
12.9k
                index,
296
12.9k
                shift,
297
12.9k
                ..
298
12.9k
            } => Self::ImmRegRegShift {
299
12.9k
                simm32,
300
12.9k
                base,
301
12.9k
                index,
302
12.9k
                shift,
303
12.9k
                flags,
304
12.9k
            },
305
0
            _ => panic!("Amode {:?} cannot take memflags", self),
306
        }
307
13.2k
    }
308
309
    /// Add the registers mentioned by `self` to `collector`.
310
283k
    pub(crate) fn get_operands<F: Fn(VReg) -> VReg>(
311
283k
        &self,
312
283k
        collector: &mut OperandCollector<'_, F>,
313
283k
    ) {
314
283k
        match self {
315
234k
            Amode::ImmReg { base, .. } => {
316
234k
                if *base != regs::rbp() && *base != regs::rsp() {
317
157k
                    collector.reg_use(*base);
318
157k
                }
319
            }
320
48.7k
            Amode::ImmRegRegShift { base, index, .. } => {
321
48.7k
                debug_assert_ne!(base.to_reg(), regs::rbp());
322
48.7k
                debug_assert_ne!(base.to_reg(), regs::rsp());
323
48.7k
                collector.reg_use(base.to_reg());
324
48.7k
                debug_assert_ne!(index.to_reg(), regs::rbp());
325
48.7k
                debug_assert_ne!(index.to_reg(), regs::rsp());
326
48.7k
                collector.reg_use(index.to_reg());
327
            }
328
0
            Amode::RipRelative { .. } => {
329
0
                // RIP isn't involved in regalloc.
330
0
            }
331
        }
332
283k
    }
333
334
    /// Same as `get_operands`, but add the registers in the "late" phase.
335
0
    pub(crate) fn get_operands_late<F: Fn(VReg) -> VReg>(
336
0
        &self,
337
0
        collector: &mut OperandCollector<'_, F>,
338
0
    ) {
339
0
        match self {
340
0
            Amode::ImmReg { base, .. } => {
341
0
                collector.reg_late_use(*base);
342
0
            }
343
0
            Amode::ImmRegRegShift { base, index, .. } => {
344
0
                collector.reg_late_use(base.to_reg());
345
0
                collector.reg_late_use(index.to_reg());
346
0
            }
347
0
            Amode::RipRelative { .. } => {
348
0
                // RIP isn't involved in regalloc.
349
0
            }
350
        }
351
0
    }
352
353
455k
    pub(crate) fn get_flags(&self) -> MemFlags {
354
455k
        match self {
355
380k
            Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags,
356
75.5k
            Amode::RipRelative { .. } => MemFlags::trusted(),
357
        }
358
455k
    }
359
360
455k
    pub(crate) fn can_trap(&self) -> bool {
361
455k
        !self.get_flags().notrap()
362
455k
    }
363
364
380k
    pub(crate) fn with_allocs(&self, allocs: &mut AllocationConsumer<'_>) -> Self {
365
380k
        // The order in which we consume allocs here must match the
366
380k
        // order in which we produce operands in get_operands() above.
367
380k
        match self {
368
            &Amode::ImmReg {
369
328k
                simm32,
370
328k
                base,
371
328k
                flags,
372
            } => {
373
328k
                let base = if base == regs::rsp() || base == regs::rbp() {
374
170k
                    base
375
                } else {
376
157k
                    allocs.next(base)
377
                };
378
328k
                Amode::ImmReg {
379
328k
                    simm32,
380
328k
                    flags,
381
328k
                    base,
382
328k
                }
383
            }
384
            &Amode::ImmRegRegShift {
385
49.4k
                simm32,
386
49.4k
                base,
387
49.4k
                index,
388
49.4k
                shift,
389
49.4k
                flags,
390
49.4k
            } => Amode::ImmRegRegShift {
391
49.4k
                simm32,
392
49.4k
                shift,
393
49.4k
                flags,
394
49.4k
                base: Gpr::new(allocs.next(*base)).unwrap(),
395
49.4k
                index: Gpr::new(allocs.next(*index)).unwrap(),
396
49.4k
            },
397
2.85k
            &Amode::RipRelative { target } => Amode::RipRelative { target },
398
        }
399
380k
    }
400
401
    /// Offset the amode by a fixed offset.
402
0
    pub(crate) fn offset(&self, offset: u32) -> Self {
403
0
        let mut ret = self.clone();
404
0
        match &mut ret {
405
0
            &mut Amode::ImmReg { ref mut simm32, .. } => *simm32 += offset,
406
0
            &mut Amode::ImmRegRegShift { ref mut simm32, .. } => *simm32 += offset,
407
0
            _ => panic!("Cannot offset amode: {:?}", self),
408
        }
409
0
        ret
410
0
    }
411
}
412
413
impl PrettyPrint for Amode {
414
0
    fn pretty_print(&self, _size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
415
0
        match self {
416
0
            Amode::ImmReg { simm32, base, .. } => {
417
0
                // Note: size is always 8; the address is 64 bits,
418
0
                // even if the addressed operand is smaller.
419
0
                format!("{}({})", *simm32 as i32, pretty_print_reg(*base, 8, allocs))
420
            }
421
            Amode::ImmRegRegShift {
422
0
                simm32,
423
0
                base,
424
0
                index,
425
0
                shift,
426
0
                ..
427
0
            } => format!(
428
0
                "{}({},{},{})",
429
0
                *simm32 as i32,
430
0
                pretty_print_reg(base.to_reg(), 8, allocs),
431
0
                pretty_print_reg(index.to_reg(), 8, allocs),
432
0
                1 << shift
433
0
            ),
434
0
            Amode::RipRelative { ref target } => format!("label{}(%rip)", target.get()),
435
        }
436
0
    }
437
}
438
439
/// A Memory Address. These denote a 64-bit value only.
440
/// Used for usual addressing modes as well as addressing modes used during compilation, when the
441
/// moving SP offset is not known.
442
#[derive(Clone, Debug)]
443
pub enum SyntheticAmode {
444
    /// A real amode.
445
    Real(Amode),
446
447
    /// A (virtual) offset to the "nominal SP" value, which will be recomputed as we push and pop
448
    /// within the function.
449
    NominalSPOffset { simm32: u32 },
450
451
    /// A virtual offset to a constant that will be emitted in the constant section of the buffer.
452
    ConstantOffset(VCodeConstant),
453
}
454
455
impl SyntheticAmode {
456
6.38k
    pub(crate) fn nominal_sp_offset(simm32: u32) -> Self {
457
6.38k
        SyntheticAmode::NominalSPOffset { simm32 }
458
6.38k
    }
459
460
    /// Add the registers mentioned by `self` to `collector`.
461
358k
    pub(crate) fn get_operands<F: Fn(VReg) -> VReg>(
462
358k
        &self,
463
358k
        collector: &mut OperandCollector<'_, F>,
464
358k
    ) {
465
358k
        match self {
466
283k
            SyntheticAmode::Real(addr) => addr.get_operands(collector),
467
0
            SyntheticAmode::NominalSPOffset { .. } => {
468
0
                // Nothing to do; the base is SP and isn't involved in regalloc.
469
0
            }
470
74.8k
            SyntheticAmode::ConstantOffset(_) => {}
471
        }
472
358k
    }
473
474
    /// Same as `get_operands`, but add the register in the "late" phase.
475
0
    pub(crate) fn get_operands_late<F: Fn(VReg) -> VReg>(
476
0
        &self,
477
0
        collector: &mut OperandCollector<'_, F>,
478
0
    ) {
479
0
        match self {
480
0
            SyntheticAmode::Real(addr) => addr.get_operands_late(collector),
481
0
            SyntheticAmode::NominalSPOffset { .. } => {
482
0
                // Nothing to do; the base is SP and isn't involved in regalloc.
483
0
            }
484
0
            SyntheticAmode::ConstantOffset(_) => {}
485
        }
486
0
    }
487
488
455k
    pub(crate) fn finalize(&self, state: &mut EmitState, buffer: &MachBuffer<Inst>) -> Amode {
489
455k
        match self {
490
374k
            SyntheticAmode::Real(addr) => addr.clone(),
491
6.38k
            SyntheticAmode::NominalSPOffset { simm32 } => {
492
6.38k
                let off = *simm32 as i64 + state.virtual_sp_offset;
493
6.38k
                // TODO will require a sequence of add etc.
494
6.38k
                assert!(
495
6.38k
                    off <= u32::max_value() as i64,
496
0
                    "amode finalize: add sequence NYI"
497
                );
498
6.38k
                Amode::imm_reg(off as u32, regs::rsp())
499
            }
500
74.8k
            SyntheticAmode::ConstantOffset(c) => {
501
74.8k
                Amode::rip_relative(buffer.get_label_for_constant(*c))
502
            }
503
        }
504
455k
    }
505
506
231k
    pub(crate) fn with_allocs(&self, allocs: &mut AllocationConsumer<'_>) -> Self {
507
231k
        match self {
508
92.0k
            SyntheticAmode::Real(addr) => SyntheticAmode::Real(addr.with_allocs(allocs)),
509
            &SyntheticAmode::NominalSPOffset { .. } | &SyntheticAmode::ConstantOffset { .. } => {
510
139k
                self.clone()
511
            }
512
        }
513
231k
    }
514
}
515
516
impl Into<SyntheticAmode> for Amode {
517
297k
    fn into(self) -> SyntheticAmode {
518
297k
        SyntheticAmode::Real(self)
519
297k
    }
520
}
521
522
impl Into<SyntheticAmode> for VCodeConstant {
523
0
    fn into(self) -> SyntheticAmode {
524
0
        SyntheticAmode::ConstantOffset(self)
525
0
    }
526
}
527
528
impl PrettyPrint for SyntheticAmode {
529
0
    fn pretty_print(&self, _size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
530
0
        match self {
531
            // See note in `Amode` regarding constant size of `8`.
532
0
            SyntheticAmode::Real(addr) => addr.pretty_print(8, allocs),
533
0
            SyntheticAmode::NominalSPOffset { simm32 } => {
534
0
                format!("rsp({} + virtual offset)", *simm32 as i32)
535
            }
536
0
            SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()),
537
        }
538
0
    }
539
}
540
541
/// An operand which is either an integer Register, a value in Memory or an Immediate.  This can
542
/// denote an 8, 16, 32 or 64 bit value.  For the Immediate form, in the 8- and 16-bit case, only
543
/// the lower 8 or 16 bits of `simm32` is relevant.  In the 64-bit case, the value denoted by
544
/// `simm32` is its sign-extension out to 64 bits.
545
#[derive(Clone, Debug)]
546
pub enum RegMemImm {
547
    Reg { reg: Reg },
548
    Mem { addr: SyntheticAmode },
549
    Imm { simm32: u32 },
550
}
551
552
impl RegMemImm {
553
251k
    pub(crate) fn reg(reg: Reg) -> Self {
554
251k
        debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
555
251k
        Self::Reg { reg }
556
251k
    }
557
6.51k
    pub(crate) fn mem(addr: impl Into<SyntheticAmode>) -> Self {
558
6.51k
        Self::Mem { addr: addr.into() }
559
6.51k
    }
<cranelift_codegen::isa::x64::inst::args::RegMemImm>::mem::<cranelift_codegen::isa::x64::inst::args::SyntheticAmode>
Line
Count
Source
557
6.48k
    pub(crate) fn mem(addr: impl Into<SyntheticAmode>) -> Self {
558
6.48k
        Self::Mem { addr: addr.into() }
559
6.48k
    }
<cranelift_codegen::isa::x64::inst::args::RegMemImm>::mem::<cranelift_codegen::isa::x64::lower::isle::generated_code::Amode>
Line
Count
Source
557
38
    pub(crate) fn mem(addr: impl Into<SyntheticAmode>) -> Self {
558
38
        Self::Mem { addr: addr.into() }
559
38
    }
560
127k
    pub(crate) fn imm(simm32: u32) -> Self {
561
127k
        Self::Imm { simm32 }
562
127k
    }
563
564
    /// Asserts that in register mode, the reg class is the one that's expected.
565
310k
    pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
566
310k
        if let Self::Reg { reg } = self {
567
183k
            debug_assert_eq!(reg.class(), expected_reg_class);
568
127k
        }
569
310k
    }
570
571
    /// Add the regs mentioned by `self` to `collector`.
572
55.8k
    pub(crate) fn get_operands<F: Fn(VReg) -> VReg>(
573
55.8k
        &self,
574
55.8k
        collector: &mut OperandCollector<'_, F>,
575
55.8k
    ) {
576
55.8k
        match self {
577
35.7k
            Self::Reg { reg } => collector.reg_use(*reg),
578
6.54k
            Self::Mem { addr } => addr.get_operands(collector),
579
13.5k
            Self::Imm { .. } => {}
580
        }
581
55.8k
    }
582
583
175k
    pub(crate) fn to_reg(&self) -> Option<Reg> {
584
175k
        match self {
585
83.6k
            Self::Reg { reg } => Some(*reg),
586
91.9k
            _ => None,
587
        }
588
175k
    }
589
590
241k
    pub(crate) fn with_allocs(&self, allocs: &mut AllocationConsumer<'_>) -> Self {
591
241k
        match self {
592
158k
            Self::Reg { reg } => Self::Reg {
593
158k
                reg: allocs.next(*reg),
594
158k
            },
595
6.17k
            Self::Mem { addr } => Self::Mem {
596
6.17k
                addr: addr.with_allocs(allocs),
597
6.17k
            },
598
76.9k
            Self::Imm { .. } => self.clone(),
599
        }
600
241k
    }
601
}
602
603
impl PrettyPrint for RegMemImm {
604
0
    fn pretty_print(&self, size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
605
0
        match self {
606
0
            Self::Reg { reg } => pretty_print_reg(*reg, size, allocs),
607
0
            Self::Mem { addr } => addr.pretty_print(size, allocs),
608
0
            Self::Imm { simm32 } => format!("${}", *simm32 as i32),
609
        }
610
0
    }
611
}
612
613
/// An operand which is either an 8-bit integer immediate or a register.
614
#[derive(Clone, Debug)]
615
pub enum Imm8Reg {
616
    Imm8 { imm: u8 },
617
    Reg { reg: Reg },
618
}
619
620
impl From<u8> for Imm8Reg {
621
0
    fn from(imm: u8) -> Self {
622
0
        Self::Imm8 { imm }
623
0
    }
624
}
625
626
impl From<Reg> for Imm8Reg {
627
0
    fn from(reg: Reg) -> Self {
628
0
        Self::Reg { reg }
629
0
    }
630
}
631
632
/// An operand which is either an integer Register or a value in Memory.  This can denote an 8, 16,
633
/// 32, 64, or 128 bit value.
634
#[derive(Clone, Debug)]
635
pub enum RegMem {
636
    Reg { reg: Reg },
637
    Mem { addr: SyntheticAmode },
638
}
639
640
impl RegMem {
641
399k
    pub(crate) fn reg(reg: Reg) -> Self {
642
399k
        debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
643
399k
        Self::Reg { reg }
644
399k
    }
645
190k
    pub(crate) fn mem(addr: impl Into<SyntheticAmode>) -> Self {
646
190k
        Self::Mem { addr: addr.into() }
647
190k
    }
<cranelift_codegen::isa::x64::inst::args::RegMem>::mem::<cranelift_codegen::isa::x64::lower::isle::generated_code::Amode>
Line
Count
Source
645
13.9k
    pub(crate) fn mem(addr: impl Into<SyntheticAmode>) -> Self {
646
13.9k
        Self::Mem { addr: addr.into() }
647
13.9k
    }
<cranelift_codegen::isa::x64::inst::args::RegMem>::mem::<cranelift_codegen::machinst::abi::StackAMode>
Line
Count
Source
645
35.2k
    pub(crate) fn mem(addr: impl Into<SyntheticAmode>) -> Self {
646
35.2k
        Self::Mem { addr: addr.into() }
647
35.2k
    }
<cranelift_codegen::isa::x64::inst::args::RegMem>::mem::<cranelift_codegen::isa::x64::inst::args::SyntheticAmode>
Line
Count
Source
645
141k
    pub(crate) fn mem(addr: impl Into<SyntheticAmode>) -> Self {
646
141k
        Self::Mem { addr: addr.into() }
647
141k
    }
648
    /// Asserts that in register mode, the reg class is the one that's expected.
649
326k
    pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
650
326k
        if let Self::Reg { reg } = self {
651
226k
            debug_assert_eq!(reg.class(), expected_reg_class);
652
100k
        }
653
326k
    }
654
    /// Add the regs mentioned by `self` to `collector`.
655
479k
    pub(crate) fn get_operands<F: Fn(VReg) -> VReg>(
656
479k
        &self,
657
479k
        collector: &mut OperandCollector<'_, F>,
658
479k
    ) {
659
479k
        match self {
660
258k
            RegMem::Reg { reg } => collector.reg_use(*reg),
661
220k
            RegMem::Mem { addr, .. } => addr.get_operands(collector),
662
        }
663
479k
    }
664
57.0k
    pub(crate) fn to_reg(&self) -> Option<Reg> {
665
57.0k
        match self {
666
56.5k
            RegMem::Reg { reg } => Some(*reg),
667
484
            _ => None,
668
        }
669
57.0k
    }
670
671
514k
    pub(crate) fn with_allocs(&self, allocs: &mut AllocationConsumer<'_>) -> Self {
672
514k
        match self {
673
305k
            RegMem::Reg { reg } => RegMem::Reg {
674
305k
                reg: allocs.next(*reg),
675
305k
            },
676
209k
            RegMem::Mem { addr } => RegMem::Mem {
677
209k
                addr: addr.with_allocs(allocs),
678
209k
            },
679
        }
680
514k
    }
681
}
682
683
impl From<Writable<Reg>> for RegMem {
684
0
    fn from(r: Writable<Reg>) -> Self {
685
0
        RegMem::reg(r.to_reg())
686
0
    }
687
}
688
689
impl PrettyPrint for RegMem {
690
0
    fn pretty_print(&self, size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
691
0
        match self {
692
0
            RegMem::Reg { reg } => pretty_print_reg(*reg, size, allocs),
693
0
            RegMem::Mem { addr, .. } => addr.pretty_print(size, allocs),
694
        }
695
0
    }
696
}
697
698
/// Some basic ALU operations.  TODO: maybe add Adc, Sbb.
699
#[derive(Copy, Clone, PartialEq)]
700
pub enum AluRmiROpcode {
701
    Add,
702
    Adc,
703
    Sub,
704
    Sbb,
705
    And,
706
    Or,
707
    Xor,
708
    /// The signless, non-extending (N x N -> N, for N in {32,64}) variant.
709
    Mul,
710
}
711
712
impl fmt::Debug for AluRmiROpcode {
713
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
714
0
        let name = match self {
715
0
            AluRmiROpcode::Add => "add",
716
0
            AluRmiROpcode::Adc => "adc",
717
0
            AluRmiROpcode::Sub => "sub",
718
0
            AluRmiROpcode::Sbb => "sbb",
719
0
            AluRmiROpcode::And => "and",
720
0
            AluRmiROpcode::Or => "or",
721
0
            AluRmiROpcode::Xor => "xor",
722
0
            AluRmiROpcode::Mul => "imul",
723
        };
724
0
        write!(fmt, "{}", name)
725
0
    }
726
}
727
728
impl fmt::Display for AluRmiROpcode {
729
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
730
0
        fmt::Debug::fmt(self, f)
731
0
    }
732
}
733
734
#[derive(Clone, PartialEq)]
735
pub enum UnaryRmROpcode {
736
    /// Bit-scan reverse.
737
    Bsr,
738
    /// Bit-scan forward.
739
    Bsf,
740
    /// Counts leading zeroes (Leading Zero CouNT).
741
    Lzcnt,
742
    /// Counts trailing zeroes (Trailing Zero CouNT).
743
    Tzcnt,
744
    /// Counts the number of ones (POPulation CouNT).
745
    Popcnt,
746
}
747
748
impl UnaryRmROpcode {
749
9.68k
    pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
750
9.68k
        match self {
751
0
            UnaryRmROpcode::Bsr | UnaryRmROpcode::Bsf => smallvec![],
752
2.31k
            UnaryRmROpcode::Lzcnt => smallvec![InstructionSet::Lzcnt],
753
3.28k
            UnaryRmROpcode::Tzcnt => smallvec![InstructionSet::BMI1],
754
4.07k
            UnaryRmROpcode::Popcnt => smallvec![InstructionSet::Popcnt],
755
        }
756
9.68k
    }
757
}
758
759
impl fmt::Debug for UnaryRmROpcode {
760
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
761
0
        match self {
762
0
            UnaryRmROpcode::Bsr => write!(fmt, "bsr"),
763
0
            UnaryRmROpcode::Bsf => write!(fmt, "bsf"),
764
0
            UnaryRmROpcode::Lzcnt => write!(fmt, "lzcnt"),
765
0
            UnaryRmROpcode::Tzcnt => write!(fmt, "tzcnt"),
766
0
            UnaryRmROpcode::Popcnt => write!(fmt, "popcnt"),
767
        }
768
0
    }
769
}
770
771
impl fmt::Display for UnaryRmROpcode {
772
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
773
0
        fmt::Debug::fmt(self, f)
774
0
    }
775
}
776
777
#[derive(Clone, Copy, PartialEq)]
778
pub enum CmpOpcode {
779
    /// CMP instruction: compute `a - b` and set flags from result.
780
    Cmp,
781
    /// TEST instruction: compute `a & b` and set flags from result.
782
    Test,
783
}
784
785
#[derive(Debug)]
786
pub(crate) enum InstructionSet {
787
    SSE,
788
    SSE2,
789
    SSSE3,
790
    SSE41,
791
    SSE42,
792
    Popcnt,
793
    Lzcnt,
794
    BMI1,
795
    #[allow(dead_code)] // never constructed (yet).
796
    BMI2,
797
    FMA,
798
    AVX512BITALG,
799
    AVX512DQ,
800
    AVX512F,
801
    AVX512VBMI,
802
    AVX512VL,
803
}
804
805
/// Some SSE operations requiring 2 operands r/m and r.
806
#[derive(Clone, Copy, PartialEq)]
807
#[allow(dead_code)] // some variants here aren't used just yet
808
pub enum SseOpcode {
809
    Addps,
810
    Addpd,
811
    Addss,
812
    Addsd,
813
    Andps,
814
    Andpd,
815
    Andnps,
816
    Andnpd,
817
    Blendvpd,
818
    Blendvps,
819
    Comiss,
820
    Comisd,
821
    Cmpps,
822
    Cmppd,
823
    Cmpss,
824
    Cmpsd,
825
    Cvtdq2ps,
826
    Cvtdq2pd,
827
    Cvtpd2ps,
828
    Cvtps2pd,
829
    Cvtsd2ss,
830
    Cvtsd2si,
831
    Cvtsi2ss,
832
    Cvtsi2sd,
833
    Cvtss2si,
834
    Cvtss2sd,
835
    Cvttpd2dq,
836
    Cvttps2dq,
837
    Cvttss2si,
838
    Cvttsd2si,
839
    Divps,
840
    Divpd,
841
    Divss,
842
    Divsd,
843
    Insertps,
844
    Maxps,
845
    Maxpd,
846
    Maxss,
847
    Maxsd,
848
    Minps,
849
    Minpd,
850
    Minss,
851
    Minsd,
852
    Movaps,
853
    Movapd,
854
    Movd,
855
    Movdqa,
856
    Movdqu,
857
    Movlhps,
858
    Movmskps,
859
    Movmskpd,
860
    Movq,
861
    Movss,
862
    Movsd,
863
    Movups,
864
    Movupd,
865
    Mulps,
866
    Mulpd,
867
    Mulss,
868
    Mulsd,
869
    Orps,
870
    Orpd,
871
    Pabsb,
872
    Pabsw,
873
    Pabsd,
874
    Packssdw,
875
    Packsswb,
876
    Packusdw,
877
    Packuswb,
878
    Paddb,
879
    Paddd,
880
    Paddq,
881
    Paddw,
882
    Paddsb,
883
    Paddsw,
884
    Paddusb,
885
    Paddusw,
886
    Palignr,
887
    Pand,
888
    Pandn,
889
    Pavgb,
890
    Pavgw,
891
    Pblendvb,
892
    Pcmpeqb,
893
    Pcmpeqw,
894
    Pcmpeqd,
895
    Pcmpeqq,
896
    Pcmpgtb,
897
    Pcmpgtw,
898
    Pcmpgtd,
899
    Pcmpgtq,
900
    Pextrb,
901
    Pextrw,
902
    Pextrd,
903
    Pinsrb,
904
    Pinsrw,
905
    Pinsrd,
906
    Pmaddubsw,
907
    Pmaddwd,
908
    Pmaxsb,
909
    Pmaxsw,
910
    Pmaxsd,
911
    Pmaxub,
912
    Pmaxuw,
913
    Pmaxud,
914
    Pminsb,
915
    Pminsw,
916
    Pminsd,
917
    Pminub,
918
    Pminuw,
919
    Pminud,
920
    Pmovmskb,
921
    Pmovsxbd,
922
    Pmovsxbw,
923
    Pmovsxbq,
924
    Pmovsxwd,
925
    Pmovsxwq,
926
    Pmovsxdq,
927
    Pmovzxbd,
928
    Pmovzxbw,
929
    Pmovzxbq,
930
    Pmovzxwd,
931
    Pmovzxwq,
932
    Pmovzxdq,
933
    Pmuldq,
934
    Pmulhw,
935
    Pmulhuw,
936
    Pmulhrsw,
937
    Pmulld,
938
    Pmullw,
939
    Pmuludq,
940
    Por,
941
    Pshufb,
942
    Pshufd,
943
    Psllw,
944
    Pslld,
945
    Psllq,
946
    Psraw,
947
    Psrad,
948
    Psrlw,
949
    Psrld,
950
    Psrlq,
951
    Psubb,
952
    Psubd,
953
    Psubq,
954
    Psubw,
955
    Psubsb,
956
    Psubsw,
957
    Psubusb,
958
    Psubusw,
959
    Ptest,
960
    Punpckhbw,
961
    Punpckhwd,
962
    Punpcklbw,
963
    Punpcklwd,
964
    Pxor,
965
    Rcpss,
966
    Roundps,
967
    Roundpd,
968
    Roundss,
969
    Roundsd,
970
    Rsqrtss,
971
    Shufps,
972
    Sqrtps,
973
    Sqrtpd,
974
    Sqrtss,
975
    Sqrtsd,
976
    Subps,
977
    Subpd,
978
    Subss,
979
    Subsd,
980
    Ucomiss,
981
    Ucomisd,
982
    Unpcklps,
983
    Xorps,
984
    Xorpd,
985
}
986
987
impl SseOpcode {
988
    /// Which `InstructionSet` is the first supporting this opcode?
989
358k
    pub(crate) fn available_from(&self) -> InstructionSet {
990
358k
        use InstructionSet::*;
991
358k
        match self {
992
            SseOpcode::Addps
993
            | SseOpcode::Addss
994
            | SseOpcode::Andps
995
            | SseOpcode::Andnps
996
            | SseOpcode::Comiss
997
            | SseOpcode::Cmpps
998
            | SseOpcode::Cmpss
999
            | SseOpcode::Cvtsi2ss
1000
            | SseOpcode::Cvtss2si
1001
            | SseOpcode::Cvttss2si
1002
            | SseOpcode::Divps
1003
            | SseOpcode::Divss
1004
            | SseOpcode::Maxps
1005
            | SseOpcode::Maxss
1006
            | SseOpcode::Minps
1007
            | SseOpcode::Minss
1008
            | SseOpcode::Movaps
1009
            | SseOpcode::Movlhps
1010
            | SseOpcode::Movmskps
1011
            | SseOpcode::Movss
1012
            | SseOpcode::Movups
1013
            | SseOpcode::Mulps
1014
            | SseOpcode::Mulss
1015
            | SseOpcode::Orps
1016
            | SseOpcode::Rcpss
1017
            | SseOpcode::Rsqrtss
1018
            | SseOpcode::Shufps
1019
            | SseOpcode::Sqrtps
1020
            | SseOpcode::Sqrtss
1021
            | SseOpcode::Subps
1022
            | SseOpcode::Subss
1023
            | SseOpcode::Ucomiss
1024
            | SseOpcode::Unpcklps
1025
80.2k
            | SseOpcode::Xorps => SSE,
1026
1027
            SseOpcode::Addpd
1028
            | SseOpcode::Addsd
1029
            | SseOpcode::Andpd
1030
            | SseOpcode::Andnpd
1031
            | SseOpcode::Cmppd
1032
            | SseOpcode::Cmpsd
1033
            | SseOpcode::Comisd
1034
            | SseOpcode::Cvtdq2ps
1035
            | SseOpcode::Cvtdq2pd
1036
            | SseOpcode::Cvtpd2ps
1037
            | SseOpcode::Cvtps2pd
1038
            | SseOpcode::Cvtsd2ss
1039
            | SseOpcode::Cvtsd2si
1040
            | SseOpcode::Cvtsi2sd
1041
            | SseOpcode::Cvtss2sd
1042
            | SseOpcode::Cvttpd2dq
1043
            | SseOpcode::Cvttps2dq
1044
            | SseOpcode::Cvttsd2si
1045
            | SseOpcode::Divpd
1046
            | SseOpcode::Divsd
1047
            | SseOpcode::Maxpd
1048
            | SseOpcode::Maxsd
1049
            | SseOpcode::Minpd
1050
            | SseOpcode::Minsd
1051
            | SseOpcode::Movapd
1052
            | SseOpcode::Movd
1053
            | SseOpcode::Movmskpd
1054
            | SseOpcode::Movq
1055
            | SseOpcode::Movsd
1056
            | SseOpcode::Movupd
1057
            | SseOpcode::Movdqa
1058
            | SseOpcode::Movdqu
1059
            | SseOpcode::Mulpd
1060
            | SseOpcode::Mulsd
1061
            | SseOpcode::Orpd
1062
            | SseOpcode::Packssdw
1063
            | SseOpcode::Packsswb
1064
            | SseOpcode::Packuswb
1065
            | SseOpcode::Paddb
1066
            | SseOpcode::Paddd
1067
            | SseOpcode::Paddq
1068
            | SseOpcode::Paddw
1069
            | SseOpcode::Paddsb
1070
            | SseOpcode::Paddsw
1071
            | SseOpcode::Paddusb
1072
            | SseOpcode::Paddusw
1073
            | SseOpcode::Pand
1074
            | SseOpcode::Pandn
1075
            | SseOpcode::Pavgb
1076
            | SseOpcode::Pavgw
1077
            | SseOpcode::Pcmpeqb
1078
            | SseOpcode::Pcmpeqw
1079
            | SseOpcode::Pcmpeqd
1080
            | SseOpcode::Pcmpgtb
1081
            | SseOpcode::Pcmpgtw
1082
            | SseOpcode::Pcmpgtd
1083
            | SseOpcode::Pextrw
1084
            | SseOpcode::Pinsrw
1085
            | SseOpcode::Pmaddubsw
1086
            | SseOpcode::Pmaddwd
1087
            | SseOpcode::Pmaxsw
1088
            | SseOpcode::Pmaxub
1089
            | SseOpcode::Pminsw
1090
            | SseOpcode::Pminub
1091
            | SseOpcode::Pmovmskb
1092
            | SseOpcode::Pmulhw
1093
            | SseOpcode::Pmulhuw
1094
            | SseOpcode::Pmullw
1095
            | SseOpcode::Pmuludq
1096
            | SseOpcode::Por
1097
            | SseOpcode::Pshufd
1098
            | SseOpcode::Psllw
1099
            | SseOpcode::Pslld
1100
            | SseOpcode::Psllq
1101
            | SseOpcode::Psraw
1102
            | SseOpcode::Psrad
1103
            | SseOpcode::Psrlw
1104
            | SseOpcode::Psrld
1105
            | SseOpcode::Psrlq
1106
            | SseOpcode::Psubb
1107
            | SseOpcode::Psubd
1108
            | SseOpcode::Psubq
1109
            | SseOpcode::Psubw
1110
            | SseOpcode::Psubsb
1111
            | SseOpcode::Psubsw
1112
            | SseOpcode::Psubusb
1113
            | SseOpcode::Psubusw
1114
            | SseOpcode::Punpckhbw
1115
            | SseOpcode::Punpckhwd
1116
            | SseOpcode::Punpcklbw
1117
            | SseOpcode::Punpcklwd
1118
            | SseOpcode::Pxor
1119
            | SseOpcode::Sqrtpd
1120
            | SseOpcode::Sqrtsd
1121
            | SseOpcode::Subpd
1122
            | SseOpcode::Subsd
1123
            | SseOpcode::Ucomisd
1124
251k
            | SseOpcode::Xorpd => SSE2,
1125
1126
            SseOpcode::Pabsb
1127
            | SseOpcode::Pabsw
1128
            | SseOpcode::Pabsd
1129
            | SseOpcode::Palignr
1130
            | SseOpcode::Pmulhrsw
1131
0
            | SseOpcode::Pshufb => SSSE3,
1132
1133
            SseOpcode::Blendvpd
1134
            | SseOpcode::Blendvps
1135
            | SseOpcode::Insertps
1136
            | SseOpcode::Packusdw
1137
            | SseOpcode::Pblendvb
1138
            | SseOpcode::Pcmpeqq
1139
            | SseOpcode::Pextrb
1140
            | SseOpcode::Pextrd
1141
            | SseOpcode::Pinsrb
1142
            | SseOpcode::Pinsrd
1143
            | SseOpcode::Pmaxsb
1144
            | SseOpcode::Pmaxsd
1145
            | SseOpcode::Pmaxuw
1146
            | SseOpcode::Pmaxud
1147
            | SseOpcode::Pminsb
1148
            | SseOpcode::Pminsd
1149
            | SseOpcode::Pminuw
1150
            | SseOpcode::Pminud
1151
            | SseOpcode::Pmovsxbd
1152
            | SseOpcode::Pmovsxbw
1153
            | SseOpcode::Pmovsxbq
1154
            | SseOpcode::Pmovsxwd
1155
            | SseOpcode::Pmovsxwq
1156
            | SseOpcode::Pmovsxdq
1157
            | SseOpcode::Pmovzxbd
1158
            | SseOpcode::Pmovzxbw
1159
            | SseOpcode::Pmovzxbq
1160
            | SseOpcode::Pmovzxwd
1161
            | SseOpcode::Pmovzxwq
1162
            | SseOpcode::Pmovzxdq
1163
            | SseOpcode::Pmuldq
1164
            | SseOpcode::Pmulld
1165
            | SseOpcode::Ptest
1166
            | SseOpcode::Roundps
1167
            | SseOpcode::Roundpd
1168
            | SseOpcode::Roundss
1169
27.2k
            | SseOpcode::Roundsd => SSE41,
1170
1171
0
            SseOpcode::Pcmpgtq => SSE42,
1172
        }
1173
358k
    }
1174
1175
    /// Returns the src operand size for an instruction.
1176
0
    pub(crate) fn src_size(&self) -> u8 {
1177
0
        match self {
1178
0
            SseOpcode::Movd => 4,
1179
0
            _ => 8,
1180
        }
1181
0
    }
1182
1183
    /// Does an XmmRmmRImm with this opcode use src1? FIXME: split
1184
    /// into separate instructions.
1185
0
    pub(crate) fn uses_src1(&self) -> bool {
1186
0
        match self {
1187
0
            SseOpcode::Pextrb => false,
1188
0
            SseOpcode::Pextrw => false,
1189
0
            SseOpcode::Pextrd => false,
1190
0
            SseOpcode::Pshufd => false,
1191
0
            SseOpcode::Roundss => false,
1192
0
            SseOpcode::Roundsd => false,
1193
0
            SseOpcode::Roundps => false,
1194
0
            SseOpcode::Roundpd => false,
1195
0
            _ => true,
1196
        }
1197
0
    }
1198
}
1199
1200
impl fmt::Debug for SseOpcode {
1201
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1202
0
        let name = match self {
1203
0
            SseOpcode::Addps => "addps",
1204
0
            SseOpcode::Addpd => "addpd",
1205
0
            SseOpcode::Addss => "addss",
1206
0
            SseOpcode::Addsd => "addsd",
1207
0
            SseOpcode::Andpd => "andpd",
1208
0
            SseOpcode::Andps => "andps",
1209
0
            SseOpcode::Andnps => "andnps",
1210
0
            SseOpcode::Andnpd => "andnpd",
1211
0
            SseOpcode::Blendvpd => "blendvpd",
1212
0
            SseOpcode::Blendvps => "blendvps",
1213
0
            SseOpcode::Cmpps => "cmpps",
1214
0
            SseOpcode::Cmppd => "cmppd",
1215
0
            SseOpcode::Cmpss => "cmpss",
1216
0
            SseOpcode::Cmpsd => "cmpsd",
1217
0
            SseOpcode::Comiss => "comiss",
1218
0
            SseOpcode::Comisd => "comisd",
1219
0
            SseOpcode::Cvtdq2ps => "cvtdq2ps",
1220
0
            SseOpcode::Cvtdq2pd => "cvtdq2pd",
1221
0
            SseOpcode::Cvtpd2ps => "cvtpd2ps",
1222
0
            SseOpcode::Cvtps2pd => "cvtps2pd",
1223
0
            SseOpcode::Cvtsd2ss => "cvtsd2ss",
1224
0
            SseOpcode::Cvtsd2si => "cvtsd2si",
1225
0
            SseOpcode::Cvtsi2ss => "cvtsi2ss",
1226
0
            SseOpcode::Cvtsi2sd => "cvtsi2sd",
1227
0
            SseOpcode::Cvtss2si => "cvtss2si",
1228
0
            SseOpcode::Cvtss2sd => "cvtss2sd",
1229
0
            SseOpcode::Cvttpd2dq => "cvttpd2dq",
1230
0
            SseOpcode::Cvttps2dq => "cvttps2dq",
1231
0
            SseOpcode::Cvttss2si => "cvttss2si",
1232
0
            SseOpcode::Cvttsd2si => "cvttsd2si",
1233
0
            SseOpcode::Divps => "divps",
1234
0
            SseOpcode::Divpd => "divpd",
1235
0
            SseOpcode::Divss => "divss",
1236
0
            SseOpcode::Divsd => "divsd",
1237
0
            SseOpcode::Insertps => "insertps",
1238
0
            SseOpcode::Maxps => "maxps",
1239
0
            SseOpcode::Maxpd => "maxpd",
1240
0
            SseOpcode::Maxss => "maxss",
1241
0
            SseOpcode::Maxsd => "maxsd",
1242
0
            SseOpcode::Minps => "minps",
1243
0
            SseOpcode::Minpd => "minpd",
1244
0
            SseOpcode::Minss => "minss",
1245
0
            SseOpcode::Minsd => "minsd",
1246
0
            SseOpcode::Movaps => "movaps",
1247
0
            SseOpcode::Movapd => "movapd",
1248
0
            SseOpcode::Movd => "movd",
1249
0
            SseOpcode::Movdqa => "movdqa",
1250
0
            SseOpcode::Movdqu => "movdqu",
1251
0
            SseOpcode::Movlhps => "movlhps",
1252
0
            SseOpcode::Movmskps => "movmskps",
1253
0
            SseOpcode::Movmskpd => "movmskpd",
1254
0
            SseOpcode::Movq => "movq",
1255
0
            SseOpcode::Movss => "movss",
1256
0
            SseOpcode::Movsd => "movsd",
1257
0
            SseOpcode::Movups => "movups",
1258
0
            SseOpcode::Movupd => "movupd",
1259
0
            SseOpcode::Mulps => "mulps",
1260
0
            SseOpcode::Mulpd => "mulpd",
1261
0
            SseOpcode::Mulss => "mulss",
1262
0
            SseOpcode::Mulsd => "mulsd",
1263
0
            SseOpcode::Orpd => "orpd",
1264
0
            SseOpcode::Orps => "orps",
1265
0
            SseOpcode::Pabsb => "pabsb",
1266
0
            SseOpcode::Pabsw => "pabsw",
1267
0
            SseOpcode::Pabsd => "pabsd",
1268
0
            SseOpcode::Packssdw => "packssdw",
1269
0
            SseOpcode::Packsswb => "packsswb",
1270
0
            SseOpcode::Packusdw => "packusdw",
1271
0
            SseOpcode::Packuswb => "packuswb",
1272
0
            SseOpcode::Paddb => "paddb",
1273
0
            SseOpcode::Paddd => "paddd",
1274
0
            SseOpcode::Paddq => "paddq",
1275
0
            SseOpcode::Paddw => "paddw",
1276
0
            SseOpcode::Paddsb => "paddsb",
1277
0
            SseOpcode::Paddsw => "paddsw",
1278
0
            SseOpcode::Paddusb => "paddusb",
1279
0
            SseOpcode::Paddusw => "paddusw",
1280
0
            SseOpcode::Palignr => "palignr",
1281
0
            SseOpcode::Pand => "pand",
1282
0
            SseOpcode::Pandn => "pandn",
1283
0
            SseOpcode::Pavgb => "pavgb",
1284
0
            SseOpcode::Pavgw => "pavgw",
1285
0
            SseOpcode::Pblendvb => "pblendvb",
1286
0
            SseOpcode::Pcmpeqb => "pcmpeqb",
1287
0
            SseOpcode::Pcmpeqw => "pcmpeqw",
1288
0
            SseOpcode::Pcmpeqd => "pcmpeqd",
1289
0
            SseOpcode::Pcmpeqq => "pcmpeqq",
1290
0
            SseOpcode::Pcmpgtb => "pcmpgtb",
1291
0
            SseOpcode::Pcmpgtw => "pcmpgtw",
1292
0
            SseOpcode::Pcmpgtd => "pcmpgtd",
1293
0
            SseOpcode::Pcmpgtq => "pcmpgtq",
1294
0
            SseOpcode::Pextrb => "pextrb",
1295
0
            SseOpcode::Pextrw => "pextrw",
1296
0
            SseOpcode::Pextrd => "pextrd",
1297
0
            SseOpcode::Pinsrb => "pinsrb",
1298
0
            SseOpcode::Pinsrw => "pinsrw",
1299
0
            SseOpcode::Pinsrd => "pinsrd",
1300
0
            SseOpcode::Pmaddubsw => "pmaddubsw",
1301
0
            SseOpcode::Pmaddwd => "pmaddwd",
1302
0
            SseOpcode::Pmaxsb => "pmaxsb",
1303
0
            SseOpcode::Pmaxsw => "pmaxsw",
1304
0
            SseOpcode::Pmaxsd => "pmaxsd",
1305
0
            SseOpcode::Pmaxub => "pmaxub",
1306
0
            SseOpcode::Pmaxuw => "pmaxuw",
1307
0
            SseOpcode::Pmaxud => "pmaxud",
1308
0
            SseOpcode::Pminsb => "pminsb",
1309
0
            SseOpcode::Pminsw => "pminsw",
1310
0
            SseOpcode::Pminsd => "pminsd",
1311
0
            SseOpcode::Pminub => "pminub",
1312
0
            SseOpcode::Pminuw => "pminuw",
1313
0
            SseOpcode::Pminud => "pminud",
1314
0
            SseOpcode::Pmovmskb => "pmovmskb",
1315
0
            SseOpcode::Pmovsxbd => "pmovsxbd",
1316
0
            SseOpcode::Pmovsxbw => "pmovsxbw",
1317
0
            SseOpcode::Pmovsxbq => "pmovsxbq",
1318
0
            SseOpcode::Pmovsxwd => "pmovsxwd",
1319
0
            SseOpcode::Pmovsxwq => "pmovsxwq",
1320
0
            SseOpcode::Pmovsxdq => "pmovsxdq",
1321
0
            SseOpcode::Pmovzxbd => "pmovzxbd",
1322
0
            SseOpcode::Pmovzxbw => "pmovzxbw",
1323
0
            SseOpcode::Pmovzxbq => "pmovzxbq",
1324
0
            SseOpcode::Pmovzxwd => "pmovzxwd",
1325
0
            SseOpcode::Pmovzxwq => "pmovzxwq",
1326
0
            SseOpcode::Pmovzxdq => "pmovzxdq",
1327
0
            SseOpcode::Pmuldq => "pmuldq",
1328
0
            SseOpcode::Pmulhw => "pmulhw",
1329
0
            SseOpcode::Pmulhuw => "pmulhuw",
1330
0
            SseOpcode::Pmulhrsw => "pmulhrsw",
1331
0
            SseOpcode::Pmulld => "pmulld",
1332
0
            SseOpcode::Pmullw => "pmullw",
1333
0
            SseOpcode::Pmuludq => "pmuludq",
1334
0
            SseOpcode::Por => "por",
1335
0
            SseOpcode::Pshufb => "pshufb",
1336
0
            SseOpcode::Pshufd => "pshufd",
1337
0
            SseOpcode::Psllw => "psllw",
1338
0
            SseOpcode::Pslld => "pslld",
1339
0
            SseOpcode::Psllq => "psllq",
1340
0
            SseOpcode::Psraw => "psraw",
1341
0
            SseOpcode::Psrad => "psrad",
1342
0
            SseOpcode::Psrlw => "psrlw",
1343
0
            SseOpcode::Psrld => "psrld",
1344
0
            SseOpcode::Psrlq => "psrlq",
1345
0
            SseOpcode::Psubb => "psubb",
1346
0
            SseOpcode::Psubd => "psubd",
1347
0
            SseOpcode::Psubq => "psubq",
1348
0
            SseOpcode::Psubw => "psubw",
1349
0
            SseOpcode::Psubsb => "psubsb",
1350
0
            SseOpcode::Psubsw => "psubsw",
1351
0
            SseOpcode::Psubusb => "psubusb",
1352
0
            SseOpcode::Psubusw => "psubusw",
1353
0
            SseOpcode::Ptest => "ptest",
1354
0
            SseOpcode::Punpckhbw => "punpckhbw",
1355
0
            SseOpcode::Punpckhwd => "punpckhwd",
1356
0
            SseOpcode::Punpcklbw => "punpcklbw",
1357
0
            SseOpcode::Punpcklwd => "punpcklwd",
1358
0
            SseOpcode::Pxor => "pxor",
1359
0
            SseOpcode::Rcpss => "rcpss",
1360
0
            SseOpcode::Roundps => "roundps",
1361
0
            SseOpcode::Roundpd => "roundpd",
1362
0
            SseOpcode::Roundss => "roundss",
1363
0
            SseOpcode::Roundsd => "roundsd",
1364
0
            SseOpcode::Rsqrtss => "rsqrtss",
1365
0
            SseOpcode::Shufps => "shufps",
1366
0
            SseOpcode::Sqrtps => "sqrtps",
1367
0
            SseOpcode::Sqrtpd => "sqrtpd",
1368
0
            SseOpcode::Sqrtss => "sqrtss",
1369
0
            SseOpcode::Sqrtsd => "sqrtsd",
1370
0
            SseOpcode::Subps => "subps",
1371
0
            SseOpcode::Subpd => "subpd",
1372
0
            SseOpcode::Subss => "subss",
1373
0
            SseOpcode::Subsd => "subsd",
1374
0
            SseOpcode::Ucomiss => "ucomiss",
1375
0
            SseOpcode::Ucomisd => "ucomisd",
1376
0
            SseOpcode::Unpcklps => "unpcklps",
1377
0
            SseOpcode::Xorps => "xorps",
1378
0
            SseOpcode::Xorpd => "xorpd",
1379
        };
1380
0
        write!(fmt, "{}", name)
1381
0
    }
1382
}
1383
1384
impl fmt::Display for SseOpcode {
1385
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1386
0
        fmt::Debug::fmt(self, f)
1387
0
    }
1388
}
1389
1390
#[derive(Clone, PartialEq)]
1391
pub enum AvxOpcode {
1392
    Vfmadd213ss,
1393
    Vfmadd213sd,
1394
    Vfmadd213ps,
1395
    Vfmadd213pd,
1396
}
1397
1398
impl AvxOpcode {
1399
    /// Which `InstructionSet`s support the opcode?
1400
0
    pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
1401
0
        match self {
1402
            AvxOpcode::Vfmadd213ss
1403
            | AvxOpcode::Vfmadd213sd
1404
            | AvxOpcode::Vfmadd213ps
1405
0
            | AvxOpcode::Vfmadd213pd => smallvec![InstructionSet::FMA],
1406
        }
1407
0
    }
1408
}
1409
1410
impl fmt::Debug for AvxOpcode {
1411
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1412
0
        let name = match self {
1413
0
            AvxOpcode::Vfmadd213ss => "vfmadd213ss",
1414
0
            AvxOpcode::Vfmadd213sd => "vfmadd213sd",
1415
0
            AvxOpcode::Vfmadd213ps => "vfmadd213ps",
1416
0
            AvxOpcode::Vfmadd213pd => "vfmadd213pd",
1417
        };
1418
0
        write!(fmt, "{}", name)
1419
0
    }
1420
}
1421
1422
impl fmt::Display for AvxOpcode {
1423
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1424
0
        fmt::Debug::fmt(self, f)
1425
0
    }
1426
}
1427
1428
#[derive(Clone, PartialEq)]
1429
pub enum Avx512Opcode {
1430
    Vcvtudq2ps,
1431
    Vpabsq,
1432
    Vpermi2b,
1433
    Vpmullq,
1434
    Vpopcntb,
1435
}
1436
1437
impl Avx512Opcode {
1438
    /// Which `InstructionSet`s support the opcode?
1439
0
    pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
1440
0
        match self {
1441
            Avx512Opcode::Vcvtudq2ps => {
1442
0
                smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL]
1443
            }
1444
0
            Avx512Opcode::Vpabsq => smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL],
1445
            Avx512Opcode::Vpermi2b => {
1446
0
                smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512VBMI]
1447
            }
1448
0
            Avx512Opcode::Vpmullq => smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512DQ],
1449
            Avx512Opcode::Vpopcntb => {
1450
0
                smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512BITALG]
1451
            }
1452
        }
1453
0
    }
1454
}
1455
1456
impl fmt::Debug for Avx512Opcode {
1457
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1458
0
        let name = match self {
1459
0
            Avx512Opcode::Vcvtudq2ps => "vcvtudq2ps",
1460
0
            Avx512Opcode::Vpabsq => "vpabsq",
1461
0
            Avx512Opcode::Vpermi2b => "vpermi2b",
1462
0
            Avx512Opcode::Vpmullq => "vpmullq",
1463
0
            Avx512Opcode::Vpopcntb => "vpopcntb",
1464
        };
1465
0
        write!(fmt, "{}", name)
1466
0
    }
1467
}
1468
1469
impl fmt::Display for Avx512Opcode {
1470
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1471
0
        fmt::Debug::fmt(self, f)
1472
0
    }
1473
}
1474
1475
/// This defines the ways a value can be extended: either signed- or zero-extension, or none for
1476
/// types that are not extended. Contrast with [ExtMode], which defines the widths from and to which
1477
/// values can be extended.
1478
#[allow(dead_code)]
1479
#[derive(Clone, PartialEq)]
1480
pub enum ExtKind {
1481
    None,
1482
    SignExtend,
1483
    ZeroExtend,
1484
}
1485
1486
/// These indicate ways of extending (widening) a value, using the Intel
1487
/// naming: B(yte) = u8, W(ord) = u16, L(ong)word = u32, Q(uad)word = u64
1488
#[derive(Clone, PartialEq)]
1489
pub enum ExtMode {
1490
    /// Byte -> Longword.
1491
    BL,
1492
    /// Byte -> Quadword.
1493
    BQ,
1494
    /// Word -> Longword.
1495
    WL,
1496
    /// Word -> Quadword.
1497
    WQ,
1498
    /// Longword -> Quadword.
1499
    LQ,
1500
}
1501
1502
impl ExtMode {
1503
    /// Calculate the `ExtMode` from passed bit lengths of the from/to types.
1504
106k
    pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> {
1505
106k
        match (from_bits, to_bits) {
1506
10.7k
            (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
1507
950
            (1, 64) | (8, 64) => Some(ExtMode::BQ),
1508
3.02k
            (16, 32) => Some(ExtMode::WL),
1509
2.09k
            (16, 64) => Some(ExtMode::WQ),
1510
89.2k
            (32, 64) => Some(ExtMode::LQ),
1511
0
            _ => None,
1512
        }
1513
106k
    }
1514
1515
    /// Return the source register size in bytes.
1516
0
    pub(crate) fn src_size(&self) -> u8 {
1517
0
        match self {
1518
0
            ExtMode::BL | ExtMode::BQ => 1,
1519
0
            ExtMode::WL | ExtMode::WQ => 2,
1520
0
            ExtMode::LQ => 4,
1521
        }
1522
0
    }
1523
1524
    /// Return the destination register size in bytes.
1525
0
    pub(crate) fn dst_size(&self) -> u8 {
1526
0
        match self {
1527
0
            ExtMode::BL | ExtMode::WL => 4,
1528
0
            ExtMode::BQ | ExtMode::WQ | ExtMode::LQ => 8,
1529
        }
1530
0
    }
1531
}
1532
1533
impl fmt::Debug for ExtMode {
1534
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1535
0
        let name = match self {
1536
0
            ExtMode::BL => "bl",
1537
0
            ExtMode::BQ => "bq",
1538
0
            ExtMode::WL => "wl",
1539
0
            ExtMode::WQ => "wq",
1540
0
            ExtMode::LQ => "lq",
1541
        };
1542
0
        write!(fmt, "{}", name)
1543
0
    }
1544
}
1545
1546
impl fmt::Display for ExtMode {
1547
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1548
0
        fmt::Debug::fmt(self, f)
1549
0
    }
1550
}
1551
1552
/// These indicate the form of a scalar shift/rotate: left, signed right, unsigned right.
1553
#[derive(Clone, Copy)]
1554
pub enum ShiftKind {
1555
    ShiftLeft,
1556
    /// Inserts zeros in the most significant bits.
1557
    ShiftRightLogical,
1558
    /// Replicates the sign bit in the most significant bits.
1559
    ShiftRightArithmetic,
1560
    RotateLeft,
1561
    RotateRight,
1562
}
1563
1564
impl fmt::Debug for ShiftKind {
1565
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1566
0
        let name = match self {
1567
0
            ShiftKind::ShiftLeft => "shl",
1568
0
            ShiftKind::ShiftRightLogical => "shr",
1569
0
            ShiftKind::ShiftRightArithmetic => "sar",
1570
0
            ShiftKind::RotateLeft => "rol",
1571
0
            ShiftKind::RotateRight => "ror",
1572
        };
1573
0
        write!(fmt, "{}", name)
1574
0
    }
1575
}
1576
1577
impl fmt::Display for ShiftKind {
1578
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1579
0
        fmt::Debug::fmt(self, f)
1580
0
    }
1581
}
1582
1583
/// What kind of division or remainer instruction this is?
1584
#[derive(Clone, Eq, PartialEq)]
1585
pub enum DivOrRemKind {
1586
    SignedDiv,
1587
    UnsignedDiv,
1588
    SignedRem,
1589
    UnsignedRem,
1590
}
1591
1592
impl DivOrRemKind {
1593
8.55k
    pub(crate) fn is_signed(&self) -> bool {
1594
8.55k
        match self {
1595
3.31k
            DivOrRemKind::SignedDiv | DivOrRemKind::SignedRem => true,
1596
5.24k
            _ => false,
1597
        }
1598
8.55k
    }
1599
1600
3.95k
    pub(crate) fn is_div(&self) -> bool {
1601
3.95k
        match self {
1602
2.52k
            DivOrRemKind::SignedDiv | DivOrRemKind::UnsignedDiv => true,
1603
1.43k
            _ => false,
1604
        }
1605
3.95k
    }
1606
}
1607
1608
/// These indicate condition code tests.  Not all are represented since not all are useful in
1609
/// compiler-generated code.
1610
#[derive(Copy, Clone)]
1611
#[repr(u8)]
1612
pub enum CC {
1613
    ///  overflow
1614
    O = 0,
1615
    /// no overflow
1616
    NO = 1,
1617
1618
    /// < unsigned
1619
    B = 2,
1620
    /// >= unsigned
1621
    NB = 3,
1622
1623
    /// zero
1624
    Z = 4,
1625
    /// not-zero
1626
    NZ = 5,
1627
1628
    /// <= unsigned
1629
    BE = 6,
1630
    /// > unsigned
1631
    NBE = 7,
1632
1633
    /// negative
1634
    S = 8,
1635
    /// not-negative
1636
    NS = 9,
1637
1638
    /// < signed
1639
    L = 12,
1640
    /// >= signed
1641
    NL = 13,
1642
1643
    /// <= signed
1644
    LE = 14,
1645
    /// > signed
1646
    NLE = 15,
1647
1648
    /// parity
1649
    P = 10,
1650
1651
    /// not parity
1652
    NP = 11,
1653
}
1654
1655
impl CC {
1656
24.5k
    pub(crate) fn from_intcc(intcc: IntCC) -> Self {
1657
24.5k
        match intcc {
1658
10.8k
            IntCC::Equal => CC::Z,
1659
320
            IntCC::NotEqual => CC::NZ,
1660
146
            IntCC::SignedGreaterThanOrEqual => CC::NL,
1661
252
            IntCC::SignedGreaterThan => CC::NLE,
1662
100
            IntCC::SignedLessThanOrEqual => CC::LE,
1663
252
            IntCC::SignedLessThan => CC::L,
1664
6.50k
            IntCC::UnsignedGreaterThanOrEqual => CC::NB,
1665
156
            IntCC::UnsignedGreaterThan => CC::NBE,
1666
5.66k
            IntCC::UnsignedLessThanOrEqual => CC::BE,
1667
270
            IntCC::UnsignedLessThan => CC::B,
1668
        }
1669
24.5k
    }
1670
1671
99.5k
    pub(crate) fn invert(&self) -> Self {
1672
99.5k
        match self {
1673
0
            CC::O => CC::NO,
1674
0
            CC::NO => CC::O,
1675
1676
3.13k
            CC::B => CC::NB,
1677
3.13k
            CC::NB => CC::B,
1678
1679
14.7k
            CC::Z => CC::NZ,
1680
40.7k
            CC::NZ => CC::Z,
1681
1682
2.76k
            CC::BE => CC::NBE,
1683
2.76k
            CC::NBE => CC::BE,
1684
1685
0
            CC::S => CC::NS,
1686
0
            CC::NS => CC::S,
1687
1688
0
            CC::L => CC::NL,
1689
0
            CC::NL => CC::L,
1690
1691
0
            CC::LE => CC::NLE,
1692
0
            CC::NLE => CC::LE,
1693
1694
32.2k
            CC::P => CC::NP,
1695
0
            CC::NP => CC::P,
1696
        }
1697
99.5k
    }
1698
1699
249k
    pub(crate) fn get_enc(self) -> u8 {
1700
249k
        self as u8
1701
249k
    }
1702
}
1703
1704
impl fmt::Debug for CC {
1705
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1706
0
        let name = match self {
1707
0
            CC::O => "o",
1708
0
            CC::NO => "no",
1709
0
            CC::B => "b",
1710
0
            CC::NB => "nb",
1711
0
            CC::Z => "z",
1712
0
            CC::NZ => "nz",
1713
0
            CC::BE => "be",
1714
0
            CC::NBE => "nbe",
1715
0
            CC::S => "s",
1716
0
            CC::NS => "ns",
1717
0
            CC::L => "l",
1718
0
            CC::NL => "nl",
1719
0
            CC::LE => "le",
1720
0
            CC::NLE => "nle",
1721
0
            CC::P => "p",
1722
0
            CC::NP => "np",
1723
        };
1724
0
        write!(fmt, "{}", name)
1725
0
    }
1726
}
1727
1728
impl fmt::Display for CC {
1729
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1730
0
        fmt::Debug::fmt(self, f)
1731
0
    }
1732
}
1733
1734
/// Encode the ways that floats can be compared. This is used in float comparisons such as `cmpps`,
1735
/// e.g.; it is distinguished from other float comparisons (e.g. `ucomiss`) in that those use EFLAGS
1736
/// whereas [FcmpImm] is used as an immediate.
1737
#[derive(Clone, Copy)]
1738
pub enum FcmpImm {
1739
    Equal = 0x00,
1740
    LessThan = 0x01,
1741
    LessThanOrEqual = 0x02,
1742
    Unordered = 0x03,
1743
    NotEqual = 0x04,
1744
    UnorderedOrGreaterThanOrEqual = 0x05,
1745
    UnorderedOrGreaterThan = 0x06,
1746
    Ordered = 0x07,
1747
}
1748
1749
impl FcmpImm {
1750
0
    pub(crate) fn encode(self) -> u8 {
1751
0
        self as u8
1752
0
    }
1753
}
1754
1755
impl From<FloatCC> for FcmpImm {
1756
0
    fn from(cond: FloatCC) -> Self {
1757
0
        match cond {
1758
0
            FloatCC::Equal => FcmpImm::Equal,
1759
0
            FloatCC::LessThan => FcmpImm::LessThan,
1760
0
            FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual,
1761
0
            FloatCC::Unordered => FcmpImm::Unordered,
1762
0
            FloatCC::NotEqual => FcmpImm::NotEqual,
1763
0
            FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual,
1764
0
            FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan,
1765
0
            FloatCC::Ordered => FcmpImm::Ordered,
1766
0
            _ => panic!("unable to create comparison predicate for {}", cond),
1767
        }
1768
0
    }
1769
}
1770
1771
/// Encode the rounding modes used as part of the Rounding Control field.
1772
/// Note, these rounding immediates only consider the rounding control field
1773
/// (i.e. the rounding mode) which only take up the first two bits when encoded.
1774
/// However the rounding immediate which this field helps make up, also includes
1775
/// bits 3 and 4 which define the rounding select and precision mask respectively.
1776
/// These two bits are not defined here and are implictly set to zero when encoded.
1777
#[derive(Clone, Copy)]
1778
pub enum RoundImm {
1779
    RoundNearest = 0x00,
1780
    RoundDown = 0x01,
1781
    RoundUp = 0x02,
1782
    RoundZero = 0x03,
1783
}
1784
1785
impl RoundImm {
1786
27.2k
    pub(crate) fn encode(self) -> u8 {
1787
27.2k
        self as u8
1788
27.2k
    }
1789
}
1790
1791
/// An operand's size in bits.
1792
#[derive(Clone, Copy, PartialEq)]
1793
pub enum OperandSize {
1794
    Size8,
1795
    Size16,
1796
    Size32,
1797
    Size64,
1798
}
1799
1800
impl OperandSize {
1801
213k
    pub(crate) fn from_bytes(num_bytes: u32) -> Self {
1802
213k
        match num_bytes {
1803
198
            1 => OperandSize::Size8,
1804
232
            2 => OperandSize::Size16,
1805
94.3k
            4 => OperandSize::Size32,
1806
118k
            8 => OperandSize::Size64,
1807
0
            _ => unreachable!("Invalid OperandSize: {}", num_bytes),
1808
        }
1809
213k
    }
1810
1811
    // Computes the OperandSize for a given type.
1812
    // For vectors, the OperandSize of the lanes is returned.
1813
213k
    pub(crate) fn from_ty(ty: Type) -> Self {
1814
213k
        Self::from_bytes(ty.lane_type().bytes())
1815
213k
    }
1816
1817
    // Check that the value of self is one of the allowed sizes.
1818
0
    pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool {
1819
0
        sizes.iter().any(|val| *self == *val)
1820
0
    }
1821
1822
34.2k
    pub(crate) fn to_bytes(&self) -> u8 {
1823
34.2k
        match self {
1824
0
            Self::Size8 => 1,
1825
0
            Self::Size16 => 2,
1826
21.9k
            Self::Size32 => 4,
1827
12.3k
            Self::Size64 => 8,
1828
        }
1829
34.2k
    }
1830
1831
27.9k
    pub(crate) fn to_bits(&self) -> u8 {
1832
27.9k
        self.to_bytes() * 8
1833
27.9k
    }
1834
}
1835
1836
/// An x64 memory fence kind.
1837
#[derive(Clone)]
1838
#[allow(dead_code)]
1839
pub enum FenceKind {
1840
    /// `mfence` instruction ("Memory Fence")
1841
    MFence,
1842
    /// `lfence` instruction ("Load Fence")
1843
    LFence,
1844
    /// `sfence` instruction ("Store Fence")
1845
    SFence,
1846
}