cranelift_assembler_x64/
rex.rs1use crate::api::CodeSink;
4
5pub(crate) fn low8_will_sign_extend_to_32(xs: i32) -> bool {
6 xs == ((xs << 24) >> 24)
7}
8
9#[inline]
11pub fn encode_modrm(m0d: u8, enc_reg_g: u8, rm_e: u8) -> u8 {
12 debug_assert!(m0d < 4);
13 debug_assert!(enc_reg_g < 8);
14 debug_assert!(rm_e < 8);
15 ((m0d & 3) << 6) | ((enc_reg_g & 7) << 3) | (rm_e & 7)
16}
17
18#[inline]
20pub fn encode_sib(scale: u8, enc_index: u8, enc_base: u8) -> u8 {
21 debug_assert!(scale < 4);
22 debug_assert!(enc_index < 8);
23 debug_assert!(enc_base < 8);
24 ((scale & 3) << 6) | ((enc_index & 7) << 3) | (enc_base & 7)
25}
26
27#[repr(transparent)]
31#[derive(Clone, Copy)]
32pub struct RexFlags(u8);
33
34impl RexFlags {
35 #[inline]
37 #[must_use]
38 pub fn set_w() -> Self {
39 Self(0)
40 }
41
42 #[inline]
44 #[must_use]
45 pub fn clear_w() -> Self {
46 Self(1)
47 }
48
49 #[inline]
51 #[must_use]
52 pub fn must_clear_w(self) -> bool {
53 (self.0 & 1) != 0
54 }
55
56 #[inline]
58 pub fn always_emit(&mut self) -> &mut Self {
59 self.0 |= 2;
60 self
61 }
62
63 #[inline]
65 #[must_use]
66 pub fn must_always_emit(self) -> bool {
67 (self.0 & 2) != 0
68 }
69
70 pub fn always_emit_if_8bit_needed(&mut self, enc: u8) {
73 if (4..=7).contains(&enc) {
74 self.always_emit();
75 }
76 }
77
78 #[inline]
80 pub fn emit_one_op(self, sink: &mut impl CodeSink, enc_e: u8) {
81 let w = if self.must_clear_w() { 0 } else { 1 };
85 let r = 0;
86 let x = 0;
87 let b = (enc_e >> 3) & 1;
88 let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b;
89 if rex != 0x40 || self.must_always_emit() {
90 sink.put1(rex);
91 }
92 }
93
94 #[inline]
96 pub fn emit_two_op(self, sink: &mut impl CodeSink, enc_g: u8, enc_e: u8) {
97 let w = if self.must_clear_w() { 0 } else { 1 };
98 let r = (enc_g >> 3) & 1;
99 let x = 0;
100 let b = (enc_e >> 3) & 1;
101 let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b;
102 if rex != 0x40 || self.must_always_emit() {
103 sink.put1(rex);
104 }
105 }
106
107 #[inline]
109 pub fn emit_three_op(self, sink: &mut impl CodeSink, enc_g: u8, enc_index: u8, enc_base: u8) {
110 let w = if self.must_clear_w() { 0 } else { 1 };
111 let r = (enc_g >> 3) & 1;
112 let x = (enc_index >> 3) & 1;
113 let b = (enc_base >> 3) & 1;
114 let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b;
115 if rex != 0x40 || self.must_always_emit() {
116 sink.put1(rex);
117 }
118 }
119}
120
121#[derive(Copy, Clone)]
122pub enum Imm {
123 None,
124 Imm8(i8),
125 Imm32(i32),
126}
127
128impl Imm {
129 pub fn new(val: i32, evex_scaling: Option<i8>) -> Imm {
143 if val == 0 {
144 return Imm::None;
145 }
146 match evex_scaling {
147 Some(scaling) => {
148 if val % i32::from(scaling) == 0 {
149 let scaled = val / i32::from(scaling);
150 if low8_will_sign_extend_to_32(scaled) {
151 return Imm::Imm8(scaled as i8);
152 }
153 }
154 Imm::Imm32(val)
155 }
156 None => match i8::try_from(val) {
157 Ok(val) => Imm::Imm8(val),
158 Err(_) => Imm::Imm32(val),
159 },
160 }
161 }
162
163 pub fn force_immediate(&mut self) {
166 if let Imm::None = self {
167 *self = Imm::Imm8(0);
168 }
169 }
170
171 pub fn m0d(self) -> u8 {
174 match self {
175 Imm::None => 0b00,
176 Imm::Imm8(_) => 0b01,
177 Imm::Imm32(_) => 0b10,
178 }
179 }
180
181 pub fn emit(self, sink: &mut impl CodeSink) {
183 match self {
184 Imm::None => {}
185 Imm::Imm8(n) => sink.put1(n as u8),
186 Imm::Imm32(n) => sink.put4(n as u32),
187 }
188 }
189}