1use crate::bit_misc::BitExtraction;
2use crate::elf::AllowedRange;
3use crate::elf::RelocationKind;
4use crate::elf::RelocationKindInfo;
5use crate::elf::RelocationSize;
6use crate::elf::RiscVInstruction;
7use crate::relaxation::RelocationModifier;
8use crate::utils::and_from_slice;
9use crate::utils::or_from_slice;
10use crate::utils::u32_from_slice;
11
12pub const JAL_RANGE: std::ops::RangeInclusive<i64> = -(1i64 << 20)..=((1i64 << 20) - 1);
14
15#[inline]
16#[must_use]
17pub fn distance_fits_jal(distance: i64) -> bool {
18 JAL_RANGE.contains(&distance)
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum RelaxationKind {
23 NoOp,
25
26 ReplaceWithNop,
28
29 CallToJal,
31
32 Hi20ToCLui,
34
35 Hi20Delete,
37
38 Lo12Rs1ToZero,
41}
42
43impl RelaxationKind {
44 pub fn apply(self, section_bytes: &mut [u8], offset_in_section: &mut u64, _addend: &mut i64) {
45 let offset = *offset_in_section as usize;
46 match self {
47 RelaxationKind::NoOp => {}
48 RelaxationKind::ReplaceWithNop => {
49 section_bytes[offset..offset + 4].copy_from_slice(&[
50 0x01, 0x0, 0x01, 0x0, ]);
53 }
54 RelaxationKind::CallToJal => {
55 let auipc_word = u32_from_slice(§ion_bytes[offset..]);
56 let rd = (auipc_word >> 7) & 0x1f;
57 let jal_base = 0x6fu32 | (rd << 7);
58 section_bytes[offset..offset + 4].copy_from_slice(&jal_base.to_le_bytes());
59 }
60 RelaxationKind::Hi20ToCLui => {
61 let lui_lo = u16::from_le_bytes([section_bytes[offset], section_bytes[offset + 1]]);
62 let rd = (lui_lo >> 7) & 0x1f;
63 let clui_base: u16 = 0x6001 | (rd << 7);
64 section_bytes[offset..offset + 2].copy_from_slice(&clui_base.to_le_bytes());
65 }
66 RelaxationKind::Hi20Delete => {}
67 RelaxationKind::Lo12Rs1ToZero => {
68 let word = u32_from_slice(§ion_bytes[offset..]);
69 let word = word & !RS1_MASK;
70 section_bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
71 }
72 }
73 }
74
75 #[must_use]
76 pub fn next_modifier(&self) -> RelocationModifier {
77 match self {
78 RelaxationKind::CallToJal | RelaxationKind::Hi20Delete => {
79 RelocationModifier::SkipNextRelocation
80 }
81 _ => RelocationModifier::Normal,
82 }
83 }
84
85 #[must_use]
88 pub fn hi20_is_zero(value: u64) -> bool {
89 let hi20 = value.wrapping_add(0x800) >> 12;
90
91 (hi20 & 0xf_ffff) == 0
92 }
93
94 #[must_use]
97 pub fn hi20_fits_clui(value: u64) -> bool {
98 let hi20 = value.wrapping_add(0x800) >> 12;
99 let hi20_signed = hi20 as i64;
100 let as_6bit = ((hi20_signed as i8) << 2) >> 2; i64::from(as_6bit) == hi20_signed && hi20_signed != 0
104 }
105
106 #[must_use]
108 pub fn rd_valid_for_clui(rd: u32) -> bool {
109 rd != 0 && rd != 2
110 }
111
112 #[must_use]
114 pub fn clui_rel_info() -> RelocationKindInfo {
115 RelocationKindInfo {
116 kind: RelocationKind::Absolute,
117 size: RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::CluiType),
118 mask: None,
119 range: AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
120 alignment: 1,
121 bias: 0,
122 thunkable: false,
123 }
124 }
125}
126
127#[must_use]
128pub const fn relocation_type_from_raw(r_type: u32) -> Option<RelocationKindInfo> {
129 let (kind, size, mask, range, alignment) = match r_type {
132 object::elf::R_RISCV_NONE => (
133 RelocationKind::None,
134 RelocationSize::ByteSize(0),
135 None,
136 AllowedRange::no_check(),
137 1,
138 ),
139 object::elf::R_RISCV_32 => (
140 RelocationKind::Absolute,
141 RelocationSize::ByteSize(4),
142 None,
143 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
144 1,
145 ),
146 object::elf::R_RISCV_64 => (
147 RelocationKind::Absolute,
148 RelocationSize::ByteSize(8),
149 None,
150 AllowedRange::no_check(),
151 1,
152 ),
153 object::elf::R_RISCV_BRANCH => (
154 RelocationKind::Relative,
155 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::BType),
156 None,
157 AllowedRange::new(-(2i64.pow(12)), 2i64.pow(12) - 1),
159 2,
160 ),
161 object::elf::R_RISCV_JAL => (
162 RelocationKind::Relative,
163 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::JType),
164 None,
165 AllowedRange::new(-(2i64.pow(20)), 2i64.pow(20) - 1),
167 2,
168 ),
169 object::elf::R_RISCV_CALL | object::elf::R_RISCV_CALL_PLT => (
170 RelocationKind::PltRelative,
171 RelocationSize::bit_mask_riscv(0, 64, RiscVInstruction::UiType),
172 None,
173 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
175 1,
176 ),
177 object::elf::R_RISCV_GOT_HI20 => (
178 RelocationKind::GotRelative,
179 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::UType),
180 None,
181 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
183 1,
184 ),
185 object::elf::R_RISCV_TLS_GOT_HI20 => (
186 RelocationKind::GotTpOff,
187 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::UType),
188 None,
189 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
191 1,
192 ),
193 object::elf::R_RISCV_TLS_GD_HI20 => (
194 RelocationKind::TlsGd,
195 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::UType),
196 None,
197 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
199 1,
200 ),
201 object::elf::R_RISCV_PCREL_HI20 => (
202 RelocationKind::Relative,
203 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::UType),
204 None,
205 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
207 1,
208 ),
209 object::elf::R_RISCV_PCREL_LO12_I => (
210 RelocationKind::RelativeRiscVLow12,
211 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::IType),
212 None,
213 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
215 1,
216 ),
217 object::elf::R_RISCV_PCREL_LO12_S => (
218 RelocationKind::RelativeRiscVLow12,
219 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::SType),
220 None,
221 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
223 1,
224 ),
225 object::elf::R_RISCV_HI20 => (
226 RelocationKind::Absolute,
227 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::UType),
228 None,
229 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
231 1,
232 ),
233 object::elf::R_RISCV_LO12_I => (
234 RelocationKind::Absolute,
235 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::IType),
236 None,
237 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
239 1,
240 ),
241 object::elf::R_RISCV_LO12_S => (
242 RelocationKind::Absolute,
243 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::SType),
244 None,
245 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
247 1,
248 ),
249 object::elf::R_RISCV_TPREL_HI20 => (
250 RelocationKind::TpOff,
251 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::UType),
252 None,
253 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
255 1,
256 ),
257 object::elf::R_RISCV_TPREL_LO12_I => (
258 RelocationKind::TpOff,
259 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::IType),
260 None,
261 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
263 1,
264 ),
265 object::elf::R_RISCV_TPREL_LO12_S => (
266 RelocationKind::TpOff,
267 RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::SType),
268 None,
269 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
271 1,
272 ),
273 object::elf::R_RISCV_TPREL_ADD => (
274 RelocationKind::None,
275 RelocationSize::ByteSize(0),
276 None,
277 AllowedRange::no_check(),
278 1,
279 ),
280 object::elf::R_RISCV_ADD8 => (
281 RelocationKind::AbsoluteAddition,
282 RelocationSize::ByteSize(1),
283 None,
284 AllowedRange::no_check(),
285 1,
286 ),
287 object::elf::R_RISCV_ADD16 => (
288 RelocationKind::AbsoluteAddition,
289 RelocationSize::ByteSize(2),
290 None,
291 AllowedRange::no_check(),
292 1,
293 ),
294 object::elf::R_RISCV_ADD32 => (
295 RelocationKind::AbsoluteAddition,
296 RelocationSize::ByteSize(4),
297 None,
298 AllowedRange::no_check(),
299 1,
300 ),
301 object::elf::R_RISCV_ADD64 => (
302 RelocationKind::AbsoluteAddition,
303 RelocationSize::ByteSize(8),
304 None,
305 AllowedRange::no_check(),
306 1,
307 ),
308 object::elf::R_RISCV_SUB8 => (
309 RelocationKind::AbsoluteSubtraction,
310 RelocationSize::ByteSize(1),
311 None,
312 AllowedRange::no_check(),
313 1,
314 ),
315 object::elf::R_RISCV_SUB16 => (
316 RelocationKind::AbsoluteSubtraction,
317 RelocationSize::ByteSize(2),
318 None,
319 AllowedRange::no_check(),
320 1,
321 ),
322 object::elf::R_RISCV_SUB32 => (
323 RelocationKind::AbsoluteSubtraction,
324 RelocationSize::ByteSize(4),
325 None,
326 AllowedRange::no_check(),
327 1,
328 ),
329 object::elf::R_RISCV_SUB64 => (
330 RelocationKind::AbsoluteSubtraction,
331 RelocationSize::ByteSize(8),
332 None,
333 AllowedRange::no_check(),
334 1,
335 ),
336 object::elf::R_RISCV_GOT32_PCREL => (
337 RelocationKind::GotRelative,
338 RelocationSize::ByteSize(4),
339 None,
340 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
342 1,
343 ),
344 object::elf::R_RISCV_ALIGN => (
345 RelocationKind::Alignment,
346 RelocationSize::ByteSize(0),
347 None,
348 AllowedRange::no_check(),
349 1,
350 ),
351 object::elf::R_RISCV_RVC_BRANCH => (
352 RelocationKind::Relative,
353 RelocationSize::bit_mask_riscv(0, 16, RiscVInstruction::CbType),
354 None,
355 AllowedRange::new(-(2i64.pow(8)), 2i64.pow(8) - 1),
356 2,
357 ),
358 object::elf::R_RISCV_RVC_JUMP => (
359 RelocationKind::Relative,
360 RelocationSize::bit_mask_riscv(0, 16, RiscVInstruction::CjType),
361 None,
362 AllowedRange::new(-(2i64.pow(11)), 2i64.pow(11) - 1),
363 2,
364 ),
365 object::elf::R_RISCV_RELAX => (
366 RelocationKind::None,
367 RelocationSize::ByteSize(0),
368 None,
369 AllowedRange::no_check(),
370 1,
371 ),
372 object::elf::R_RISCV_SUB6 => (
373 RelocationKind::AbsoluteSubtractionWord6,
374 RelocationSize::ByteSize(1),
375 None,
376 AllowedRange::no_check(),
377 1,
378 ),
379 object::elf::R_RISCV_SET6 => (
380 RelocationKind::AbsoluteSetWord6,
381 RelocationSize::ByteSize(1),
382 None,
383 AllowedRange::no_check(),
384 1,
385 ),
386 object::elf::R_RISCV_SET8 => (
387 RelocationKind::AbsoluteSet,
388 RelocationSize::ByteSize(1),
389 None,
390 AllowedRange::no_check(),
391 1,
392 ),
393 object::elf::R_RISCV_SET16 => (
394 RelocationKind::AbsoluteSet,
395 RelocationSize::ByteSize(2),
396 None,
397 AllowedRange::no_check(),
398 1,
399 ),
400 object::elf::R_RISCV_SET32 => (
401 RelocationKind::AbsoluteSet,
402 RelocationSize::ByteSize(4),
403 None,
404 AllowedRange::no_check(),
405 1,
406 ),
407 object::elf::R_RISCV_32_PCREL => (
408 RelocationKind::Relative,
409 RelocationSize::ByteSize(4),
410 None,
411 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
413 1,
414 ),
415 object::elf::R_RISCV_PLT32 => (
416 RelocationKind::PltRelative,
417 RelocationSize::ByteSize(4),
418 None,
419 AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
421 1,
422 ),
423 object::elf::R_RISCV_SET_ULEB128 => (
426 RelocationKind::Relative,
427 RelocationSize::ByteSize(0),
428 None,
429 AllowedRange::no_check(),
430 1,
431 ),
432 object::elf::R_RISCV_SUB_ULEB128 => (
433 RelocationKind::PairSubtractionULEB128(object::elf::R_RISCV_SET_ULEB128),
434 RelocationSize::ByteSize(8),
435 None,
436 AllowedRange::no_check(),
437 1,
438 ),
439 object::elf::R_RISCV_TLSDESC_HI20 => return None,
441 object::elf::R_RISCV_TLSDESC_LOAD_LO12 => return None,
442 object::elf::R_RISCV_TLSDESC_ADD_LO12 => return None,
443 object::elf::R_RISCV_TLSDESC_CALL => return None,
444 _ => return None,
445 };
446
447 Some(RelocationKindInfo {
448 kind,
449 size,
450 mask,
451 range,
452 alignment,
453 bias: 0,
454 thunkable: false,
455 })
456}
457
458const RS1_MASK: u32 = 0x1f << 15;
460
461const UTYPE_IMMEDIATE_MASK: u32 = 0b0000_0000_0000_0000_0000_1111_1111_1111;
462const ITYPE_IMMEDIATE_MASK: u32 = 0b0000_0000_0000_1111_1111_1111_1111_1111;
463const STYPE_IMMEDIATE_MASK: u32 = 0b0000_0001_1111_1111_1111_0000_0111_1111;
464const BTYPE_IMMEDIATE_MASK: u32 = 0b0000_0001_1111_1111_1111_0000_0111_1111;
465const JTYPE_IMMEDIATE_MASK: u32 = 0b0000_0000_0000_0000_0000_1111_1111_1111;
466
467const CBTYPE_IMMEDIATE_MASK: u16 = 0b1110_0011_1000_0011;
468const CJTYPE_IMMEDIATE_MASK: u16 = 0b1110_0000_0000_0011;
469const CLUITYPE_IMMEDIATE_MASK: u16 = 0b1110_1111_1000_0011;
471
472impl RiscVInstruction {
473 pub fn write_to_value(self, extracted_value: u64, _negative: bool, dest: &mut [u8]) {
481 match self {
482 RiscVInstruction::UiType => {
483 RiscVInstruction::UType.write_to_value(extracted_value, _negative, &mut dest[..4]);
484 RiscVInstruction::IType.write_to_value(extracted_value, _negative, &mut dest[4..]);
485 }
486 RiscVInstruction::UType => {
487 let mask = (extracted_value
492 .wrapping_add(0x800)
493 .extract_bit_range(12..32) as u32)
494 << 12;
495 and_from_slice(dest, UTYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
496 or_from_slice(dest, &mask.to_le_bytes());
497 }
498 RiscVInstruction::IType => {
499 let mask = extracted_value << 20;
500 and_from_slice(dest, ITYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
501 or_from_slice(dest, &(mask as u32).to_le_bytes());
502 }
503 RiscVInstruction::SType => {
504 let mut mask = extracted_value.extract_bit_range(0..5) << 7;
505 mask |= extracted_value.extract_bit_range(5..12) << 25;
506 and_from_slice(dest, STYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
507 or_from_slice(dest, &(mask as u32).to_le_bytes());
508 }
509 RiscVInstruction::BType => {
510 let mut mask = extracted_value.extract_bit(11) << 7;
511 mask |= extracted_value.extract_bit_range(1..5) << 8;
512 mask |= extracted_value.extract_bit_range(5..11) << 25;
513 mask |= extracted_value.extract_bit(12) << 31;
514 and_from_slice(dest, BTYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
515 or_from_slice(dest, &(mask as u32).to_le_bytes());
516 }
517 RiscVInstruction::JType => {
518 let mut mask = extracted_value.extract_bit_range(12..20) << 12;
519 mask |= extracted_value.extract_bit(11) << 20;
520 mask |= extracted_value.extract_bit_range(1..11) << 21;
521 mask |= extracted_value.extract_bit(20) << 31;
522 and_from_slice(dest, JTYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
523 or_from_slice(dest, &(mask as u32).to_le_bytes());
524 }
525 RiscVInstruction::CbType => {
526 let mut mask = extracted_value.extract_bit(5) << 2;
527 mask |= extracted_value.extract_bit_range(1..3) << 3;
528 mask |= extracted_value.extract_bit_range(6..8) << 5;
529 mask |= extracted_value.extract_bit_range(3..5) << 10;
531 mask |= extracted_value.extract_bit(8) << 12;
532 and_from_slice(dest, CBTYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
534 or_from_slice(dest, &mask.to_le_bytes()[..2]);
535 }
536 RiscVInstruction::CjType => {
537 let mut mask = extracted_value.extract_bit(5) << 2;
538 mask |= extracted_value.extract_bit_range(1..4) << 3;
539 mask |= extracted_value.extract_bit(7) << 6;
540 mask |= extracted_value.extract_bit(6) << 7;
541 mask |= extracted_value.extract_bit(10) << 8;
542 mask |= extracted_value.extract_bit_range(8..10) << 9;
543 mask |= extracted_value.extract_bit(4) << 11;
544 mask |= extracted_value.extract_bit(11) << 12;
545 and_from_slice(dest, CJTYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
547 or_from_slice(dest, &mask.to_le_bytes()[..2]);
548 }
549 RiscVInstruction::CluiType => {
550 let hi20 = extracted_value.wrapping_add(0x800) >> 12;
551 let mut mask = (hi20 & 0x1f) << 2; mask |= ((hi20 >> 5) & 1) << 12; and_from_slice(dest, CLUITYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
554 or_from_slice(dest, &(mask as u16).to_le_bytes());
555 }
556 };
557 }
558
559 #[must_use]
562 pub fn read_value(self, bytes: &[u8]) -> (u64, bool) {
563 match self {
564 RiscVInstruction::UiType => {
565 let (hi, _) = RiscVInstruction::UType.read_value(&bytes[..4]);
566 let (lo, _) = RiscVInstruction::IType.read_value(&bytes[4..]);
567 (hi << 12 | lo, false)
568 }
569 RiscVInstruction::UType => {
570 let value = u32_from_slice(bytes);
571 let imm = (value >> 12) & 0xfffff;
572 let adjusted = ((imm as i32) << 12) >> 12;
573 ((adjusted as u64).wrapping_sub(0x800), false)
574 }
575 RiscVInstruction::IType => {
576 let value = u32_from_slice(bytes);
577 let imm = (value >> 20) & 0xfff;
578 let sign_extended = ((imm as i32) << 20) >> 20;
579 (sign_extended as u64, sign_extended < 0)
580 }
581 RiscVInstruction::SType => {
582 let value = u32_from_slice(bytes);
583 let imm_low = (value >> 7) & 0x1f;
584 let imm_high = (value >> 25) & 0x7f;
585 let imm = (imm_high << 5) | imm_low;
586 let sign_extended = ((imm as i32) << 20) >> 20;
587 (sign_extended as u64, sign_extended < 0)
588 }
589 RiscVInstruction::BType => {
590 let value = u32_from_slice(bytes);
591 let imm11 = (value >> 7) & 0x1;
592 let imm1_4 = (value >> 8) & 0xf;
593 let imm5_10 = (value >> 25) & 0x3f;
594 let imm12 = (value >> 31) & 0x1;
595
596 let imm = (imm12 << 12) | (imm11 << 11) | (imm5_10 << 5) | (imm1_4 << 1);
597 let sign_extended = ((imm as i32) << 19) >> 19;
598 (sign_extended as u64, sign_extended < 0)
599 }
600 RiscVInstruction::JType => {
601 let value = u32_from_slice(bytes);
602 let imm12_19 = (value >> 12) & 0xff;
603 let imm11 = (value >> 20) & 0x1;
604 let imm1_10 = (value >> 21) & 0x3ff;
605 let imm20 = (value >> 31) & 0x1;
606
607 let imm = (imm20 << 20) | (imm12_19 << 12) | (imm11 << 11) | (imm1_10 << 1);
608 let sign_extended = ((imm as i32) << 11) >> 11;
609 (sign_extended as u64, sign_extended < 0)
610 }
611 RiscVInstruction::CbType => {
612 let value = u16::from_le_bytes([bytes[0], bytes[1]]);
613 let imm5 = (value >> 2) & 0x1;
614 let imm1_2 = (value >> 3) & 0x3;
615 let imm6_7 = (value >> 5) & 0x3;
616 let imm3_4 = (value >> 10) & 0x3;
617 let imm8 = (value >> 12) & 0x1;
618
619 let imm = (imm8 << 8) | (imm6_7 << 6) | (imm5 << 5) | (imm3_4 << 3) | (imm1_2 << 1);
620 let sign_extended = (i32::from(imm) << 23) >> 23;
621 (sign_extended as u64, sign_extended < 0)
622 }
623 RiscVInstruction::CjType => {
624 let value = u16::from_le_bytes([bytes[0], bytes[1]]);
625 let imm5 = (value >> 2) & 0x1;
626 let imm1_3 = (value >> 3) & 0x7;
627 let imm7 = (value >> 6) & 0x1;
628 let imm6 = (value >> 7) & 0x1;
629 let imm10 = (value >> 8) & 0x1;
630 let imm8_9 = (value >> 9) & 0x3;
631 let imm4 = (value >> 11) & 0x1;
632 let imm11 = (value >> 12) & 0x1;
633
634 let imm = (imm11 << 11)
635 | (imm10 << 10)
636 | (imm8_9 << 8)
637 | (imm7 << 7)
638 | (imm6 << 6)
639 | (imm5 << 5)
640 | (imm4 << 4)
641 | (imm1_3 << 1);
642 let sign_extended = (i32::from(imm) << 20) >> 20;
643 (sign_extended as u64, sign_extended < 0)
644 }
645 RiscVInstruction::CluiType => {
646 let value = u16::from_le_bytes([bytes[0], bytes[1]]);
647 let nzimm4_0 = (value >> 2) & 0x1f;
648 let nzimm5 = (value >> 12) & 0x1;
649 let nzimm = (nzimm5 << 5) | nzimm4_0;
650 let hi20 = ((i32::from(nzimm) << 26) >> 26) as u64;
651 let extracted = (hi20 << 12).wrapping_sub(0x800);
652 (extracted, (hi20 as i64) < 0)
653 }
654 }
655 }
656}
657
658#[test]
659fn test_riscv_insn_immediate_mask() {
660 for (mask, insn) in &[
661 (UTYPE_IMMEDIATE_MASK, RiscVInstruction::UType),
662 (ITYPE_IMMEDIATE_MASK, RiscVInstruction::IType),
663 (STYPE_IMMEDIATE_MASK, RiscVInstruction::SType),
664 (BTYPE_IMMEDIATE_MASK, RiscVInstruction::BType),
665 (JTYPE_IMMEDIATE_MASK, RiscVInstruction::JType),
666 ] {
667 let mut dest = [0u8; 4];
668 let value = if matches!(insn, RiscVInstruction::UType) {
669 u64::MAX.wrapping_sub(0x800)
670 } else {
671 u64::MAX
672 };
673 insn.write_to_value(value, false, &mut dest);
674 assert_eq!(!mask, u32::from_le_bytes(dest));
675 }
676}
677
678#[test]
679fn test_riscv_insn_rvcimmediate_mask() {
680 for (mask, insn) in &[
681 (CBTYPE_IMMEDIATE_MASK, RiscVInstruction::CbType),
682 (CJTYPE_IMMEDIATE_MASK, RiscVInstruction::CjType),
683 ] {
684 let mut dest = [0u8; 2];
685 insn.write_to_value(u64::from(u16::MAX), false, &mut dest);
686 assert_eq!(!mask, u16::from_le_bytes(dest));
687 }
688}