miri/intrinsics/x86/
gfni.rs1use rustc_span::Symbol;
2
3use crate::*;
4
5impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
6pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
7 fn emulate_x86_gfni_intrinsic(
8 &mut self,
9 link_name: Symbol,
10 args: &[OpTy<'tcx>],
11 dest: &MPlaceTy<'tcx>,
12 ) -> InterpResult<'tcx, EmulateItemResult> {
13 let this = self.eval_context_mut();
14
15 let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap();
17
18 this.expect_target_feature_for_intrinsic(link_name, "gfni")?;
19 if unprefixed_name.ends_with(".256") {
20 this.expect_target_feature_for_intrinsic(link_name, "avx")?;
21 } else if unprefixed_name.ends_with(".512") {
22 this.expect_target_feature_for_intrinsic(link_name, "avx512f")?;
23 }
24
25 match unprefixed_name {
26 "vgf2p8affineqb.128" | "vgf2p8affineqb.256" | "vgf2p8affineqb.512" => {
30 let [left, right, imm8] = this.check_shim_sig_unadjusted(link_name, args)?;
31 affine_transform(this, left, right, imm8, dest, false)?;
32 }
33 "vgf2p8affineinvqb.128" | "vgf2p8affineinvqb.256" | "vgf2p8affineinvqb.512" => {
37 let [left, right, imm8] = this.check_shim_sig_unadjusted(link_name, args)?;
38 affine_transform(this, left, right, imm8, dest, true)?;
39 }
40 "vgf2p8mulb.128" | "vgf2p8mulb.256" | "vgf2p8mulb.512" => {
46 let [left, right] = this.check_shim_sig_unadjusted(link_name, args)?;
47 let (left, left_len) = this.project_to_simd(left)?;
48 let (right, right_len) = this.project_to_simd(right)?;
49 let (dest, dest_len) = this.project_to_simd(dest)?;
50
51 assert_eq!(left_len, right_len);
52 assert_eq!(dest_len, right_len);
53
54 for i in 0..dest_len {
55 let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u8()?;
56 let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u8()?;
57 let dest = this.project_index(&dest, i)?;
58 this.write_scalar(Scalar::from_u8(gf2p8_mul(left, right)), &dest)?;
59 }
60 }
61 _ => return interp_ok(EmulateItemResult::NotSupported),
62 }
63 interp_ok(EmulateItemResult::NeedsReturn)
64 }
65}
66
67fn affine_transform<'tcx>(
72 ecx: &mut MiriInterpCx<'tcx>,
73 left: &OpTy<'tcx>,
74 right: &OpTy<'tcx>,
75 imm8: &OpTy<'tcx>,
76 dest: &MPlaceTy<'tcx>,
77 inverse: bool,
78) -> InterpResult<'tcx, ()> {
79 let (left, left_len) = ecx.project_to_simd(left)?;
80 let (right, right_len) = ecx.project_to_simd(right)?;
81 let (dest, dest_len) = ecx.project_to_simd(dest)?;
82
83 assert_eq!(dest_len, right_len);
84 assert_eq!(dest_len, left_len);
85
86 let imm8 = ecx.read_scalar(imm8)?.to_u8()?;
87
88 for i in (0..dest_len).step_by(8) {
91 let mut matrix = [0u8; 8];
93 for j in 0..8 {
94 matrix[usize::try_from(j).unwrap()] =
95 ecx.read_scalar(&ecx.project_index(&right, i.wrapping_add(j))?)?.to_u8()?;
96 }
97
98 for j in 0..8 {
100 let index = i.wrapping_add(j);
101 let left = ecx.read_scalar(&ecx.project_index(&left, index)?)?.to_u8()?;
102 let left = if inverse { TABLE[usize::from(left)] } else { left };
103
104 let mut res = 0;
105
106 for bit in 0u8..8 {
108 let mut b = matrix[usize::from(bit)] & left;
109
110 b = (b & 0b1111) ^ (b >> 4);
112 b = (b & 0b11) ^ (b >> 2);
113 b = (b & 0b1) ^ (b >> 1);
114
115 res |= b << 7u8.wrapping_sub(bit);
116 }
117
118 res ^= imm8;
120
121 let dest = ecx.project_index(&dest, index)?;
122 ecx.write_scalar(Scalar::from_u8(res), &dest)?;
123 }
124 }
125
126 interp_ok(())
127}
128
129static TABLE: [u8; 256] = {
134 let mut array = [0; 256];
135
136 let mut i = 1;
137 while i < 256 {
138 #[expect(clippy::as_conversions)] let mut x = i as u8;
140 let mut y = gf2p8_mul(x, x);
141 x = y;
142 let mut j = 2;
143 while j < 8 {
144 x = gf2p8_mul(x, x);
145 y = gf2p8_mul(x, y);
146 j += 1;
147 }
148 array[i] = y;
149 i += 1;
150 }
151
152 array
153};
154
155#[expect(clippy::as_conversions)]
161const fn gf2p8_mul(left: u8, right: u8) -> u8 {
162 const POLYNOMIAL: u32 = 0x11b;
167
168 let left = left as u32;
169 let right = right as u32;
170
171 let mut result = 0u32;
172
173 let mut i = 0u32;
174 while i < 8 {
175 if left & (1 << i) != 0 {
176 result ^= right << i;
177 }
178 i = i.wrapping_add(1);
179 }
180
181 let mut i = 14u32;
182 while i >= 8 {
183 if result & (1 << i) != 0 {
184 result ^= POLYNOMIAL << i.wrapping_sub(8);
185 }
186 i = i.wrapping_sub(1);
187 }
188
189 result as u8
190}