blob: 0dd7af25b5994e44171b98b534ff5aae436a4590 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
/// How much to shift the immediate by.
pub enum Shift {
LSL0 = 0b0, // no shift
LSL12 = 0b1 // logical shift left by 12 bits
}
/// Some instructions accept a 12-bit immediate that has an optional shift
/// attached to it. This allows encoding larger values than just fit into 12
/// bits. We attempt to encode those here. If the values are too large we have
/// to bail out.
pub struct ShiftedImmediate {
shift: Shift,
value: u16
}
impl TryFrom<u64> for ShiftedImmediate {
type Error = ();
/// Attempt to convert a u64 into a BitmaskImm.
fn try_from(value: u64) -> Result<Self, Self::Error> {
let current = value;
if current < 2_u64.pow(12) {
return Ok(ShiftedImmediate { shift: Shift::LSL0, value: current as u16 });
}
if (current & (2_u64.pow(12) - 1) == 0) && ((current >> 12) < 2_u64.pow(12)) {
return Ok(ShiftedImmediate { shift: Shift::LSL12, value: (current >> 12) as u16 });
}
Err(())
}
}
impl From<ShiftedImmediate> for u32 {
/// Encode a bitmask immediate into a 32-bit value.
fn from(imm: ShiftedImmediate) -> Self {
0
| (((imm.shift as u32) & 1) << 12)
| (imm.value as u32)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_no_shift() {
let value = 256;
let result = ShiftedImmediate::try_from(value);
assert!(matches!(result, Ok(ShiftedImmediate { shift: Shift::LSL0, value })));
}
#[test]
fn test_maximum_no_shift() {
let value = (1 << 12) - 1;
let result = ShiftedImmediate::try_from(value);
assert!(matches!(result, Ok(ShiftedImmediate { shift: Shift::LSL0, value })));
}
#[test]
fn test_with_shift() {
let result = ShiftedImmediate::try_from(256 << 12);
assert!(matches!(result, Ok(ShiftedImmediate { shift: Shift::LSL12, value: 256 })));
}
#[test]
fn test_unencodable() {
let result = ShiftedImmediate::try_from((256 << 12) + 1);
assert!(matches!(result, Err(())));
}
}
|