ab_riscv_interpreter/v/zvexx/widen_narrow/
zvexx_widen_narrow_helpers.rs1use crate::v::vector_registers::{VRegGroup, VectorRegistersExt};
4pub use crate::v::zvexx::arith::zvexx_arith_helpers::OpSrc;
5use crate::v::zvexx::load::zvexx_load_helpers::{mask_bit, snapshot_mask};
6use crate::v::zvexx::zvexx_helpers::{ExtensionSew, WideningSew};
7use ab_riscv_primitives::instructions::v::Vsew;
8use ab_riscv_primitives::prelude::*;
9use core::hint::cold_path;
10
11#[inline(always)]
13#[doc(hidden)]
14#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
15pub fn sign_extend_bits(val: u64, sew: Vsew) -> i64 {
16 let shift = u64::BITS - u32::from(sew.bits_width());
17 (val.cast_signed() << shift) >> shift
18}
19
20#[inline(always)]
41#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
42fn scalar_unsigned_for_sew(val: u64, sew: Vsew) -> u64 {
43 val & (u64::MAX >> (u64::BITS - u32::from(sew.bits_width())))
44}
45
46#[inline(always)]
68#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
69fn scalar_signed_for_sew(val: u64, sew: Vsew) -> u64 {
70 sign_extend_bits(val, sew).cast_unsigned()
71}
72
73#[inline(always)]
84#[doc(hidden)]
85#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
86pub fn execute_widen_op<const ZERO_EXTEND_AB: bool, Reg, Env, F>(
87 env: &mut Env,
88 vd: VRegGroup<Env::Hart>,
89 vs2: VRegGroup<Env::Hart>,
90 src: OpSrc<VRegGroup<Env::Hart>>,
91 vm: bool,
92 sew: WideningSew<Env::Hart>,
93 op: F,
94) where
95 Reg: Register,
96 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
97 F: Fn(u64, u64) -> u64,
98{
99 let vl = vd.vl();
100 let (Some(vs2), Some(src)) = (vs2.with_same_vl(vl), src.with_same_vl(vl)) else {
101 cold_path();
102 return;
103 };
104 let sew = sew.narrow();
105
106 let mask_buf = snapshot_mask(env.read_vregs(), vm);
107
108 for i in vl.indices() {
109 if !mask_bit(&mask_buf, i) {
110 continue;
111 }
112 let raw_a = env
113 .read_vregs()
114 .read(vs2, i)
115 .expect("`vs2` has the same `vl` as `vd`, checked above; qed");
116 let wide_a = if ZERO_EXTEND_AB {
117 raw_a
118 } else {
119 sign_extend_bits(raw_a, sew).cast_unsigned()
120 };
121 let wide_b = match src.vreg {
122 Some(vs1) => {
123 let raw_b = env
124 .read_vregs()
125 .read(vs1, i)
126 .expect("`vs1` has the same `vl` as `vd`, checked above; qed");
127 if ZERO_EXTEND_AB {
128 raw_b
129 } else {
130 sign_extend_bits(raw_b, sew).cast_unsigned()
131 }
132 }
133 None => {
134 if ZERO_EXTEND_AB {
135 scalar_unsigned_for_sew(src.scalar, sew)
136 } else {
137 scalar_signed_for_sew(src.scalar, sew)
138 }
139 }
140 };
141 let result = op(wide_a, wide_b);
142 env.write_vregs()
143 .write(vd, i, result)
144 .expect("`i < vl` of `vd`; qed");
145 }
146 env.mark_vs_dirty();
147}
148
149#[inline(always)]
157#[doc(hidden)]
158#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
159pub fn execute_widen_w_op<const ZERO_EXTEND_B: bool, Reg, Env, F>(
160 env: &mut Env,
161 vd: VRegGroup<Env::Hart>,
162 vs2: VRegGroup<Env::Hart>,
163 src: OpSrc<VRegGroup<Env::Hart>>,
164 vm: bool,
165 sew: WideningSew<Env::Hart>,
166 op: F,
167) where
168 Reg: Register,
169 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
170 F: Fn(u64, u64) -> u64,
171{
172 let vl = vd.vl();
173 let (Some(vs2), Some(src)) = (vs2.with_same_vl(vl), src.with_same_vl(vl)) else {
174 cold_path();
175 return;
176 };
177 let sew = sew.narrow();
178
179 let mask_buf = snapshot_mask(env.read_vregs(), vm);
180
181 for i in vl.indices() {
182 if !mask_bit(&mask_buf, i) {
183 continue;
184 }
185 let wide_a = env
187 .read_vregs()
188 .read(vs2, i)
189 .expect("`vs2` has the same `vl` as `vd`, checked above; qed");
190 let wide_b = match src.vreg {
191 Some(vs1) => {
192 let raw_b = env
193 .read_vregs()
194 .read(vs1, i)
195 .expect("`vs1` has the same `vl` as `vd`, checked above; qed");
196 if ZERO_EXTEND_B {
197 raw_b
198 } else {
199 sign_extend_bits(raw_b, sew).cast_unsigned()
200 }
201 }
202 None => {
203 if ZERO_EXTEND_B {
204 scalar_unsigned_for_sew(src.scalar, sew)
205 } else {
206 scalar_signed_for_sew(src.scalar, sew)
207 }
208 }
209 };
210 let result = op(wide_a, wide_b);
211 env.write_vregs()
212 .write(vd, i, result)
213 .expect("`i < vl` of `vd`; qed");
214 }
215 env.mark_vs_dirty();
216}
217
218#[inline(always)]
227#[doc(hidden)]
228#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
229pub fn execute_narrow_shift<const ARITHMETIC: bool, Reg, Env>(
230 env: &mut Env,
231 vd: VRegGroup<Env::Hart>,
232 vs2: VRegGroup<Env::Hart>,
233 src: OpSrc<VRegGroup<Env::Hart>>,
234 vm: bool,
235 sew: WideningSew<Env::Hart>,
236) where
237 Reg: Register,
238 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
239{
240 let vl = vd.vl();
241 let (Some(vs2), Some(src)) = (vs2.with_same_vl(vl), src.with_same_vl(vl)) else {
242 cold_path();
243 return;
244 };
245 let wide_sew = sew.wide();
246 let sew = sew.narrow();
247 let shamt_mask = u64::from(wide_sew.bits_width() - 1);
249
250 let mask_buf = snapshot_mask(env.read_vregs(), vm);
251
252 for i in vl.indices() {
253 if !mask_bit(&mask_buf, i) {
254 continue;
255 }
256 let wide_val = env
257 .read_vregs()
258 .read(vs2, i)
259 .expect("`vs2` has the same `vl` as `vd`, checked above; qed");
260 let shamt = match src.vreg {
261 Some(vs1) => {
262 let raw = env
263 .read_vregs()
264 .read(vs1, i)
265 .expect("`vs1` has the same `vl` as `vd`, checked above; qed");
266 raw & shamt_mask
267 }
268 None => src.scalar & shamt_mask,
270 };
271 let result_wide = if ARITHMETIC {
272 (sign_extend_bits(wide_val, wide_sew) >> shamt).cast_unsigned()
276 } else {
277 wide_val >> shamt
278 };
279 let result = result_wide & ((1u64 << sew.bits_width()) - 1);
281 env.write_vregs()
282 .write(vd, i, result)
283 .expect("`i < vl` of `vd`; qed");
284 }
285 env.mark_vs_dirty();
286}
287
288#[inline(always)]
299#[doc(hidden)]
300#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
301pub fn execute_extension<const SIGN: bool, Reg, Env>(
302 env: &mut Env,
303 vd: VRegGroup<Env::Hart>,
304 vs2: VRegGroup<Env::Hart>,
305 vm: bool,
306 sew: ExtensionSew,
307) where
308 Reg: Register,
309 Env: VectorRegistersExt<Hart: HartConfig<Reg = Reg>>,
310{
311 let vl = vd.vl();
312 let Some(vs2) = vs2.with_same_vl(vl) else {
313 cold_path();
314 return;
315 };
316 let src_sew = sew.source();
317
318 let mask_buf = snapshot_mask(env.read_vregs(), vm);
319
320 for i in vl.indices() {
321 if !mask_bit(&mask_buf, i) {
322 continue;
323 }
324 let raw = env
325 .read_vregs()
326 .read(vs2, i)
327 .expect("`vs2` has the same `vl` as `vd`, checked above; qed");
328 let result = if SIGN {
329 sign_extend_bits(raw, src_sew).cast_unsigned()
330 } else {
331 raw
332 };
333 env.write_vregs()
334 .write(vd, i, result)
335 .expect("`i < vl` of `vd`; qed");
336 }
337 env.mark_vs_dirty();
338}