/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 | | } |