1use rustc_middle::ty::Ty;
8use rustc_span::Symbol;
9use rustc_target::callconv::{Conv, FnAbi};
10
11use crate::*;
12
13impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
14pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
15 fn emulate_x86_sha_intrinsic(
16 &mut self,
17 link_name: Symbol,
18 abi: &FnAbi<'tcx, Ty<'tcx>>,
19 args: &[OpTy<'tcx>],
20 dest: &MPlaceTy<'tcx>,
21 ) -> InterpResult<'tcx, EmulateItemResult> {
22 let this = self.eval_context_mut();
23 this.expect_target_feature_for_intrinsic(link_name, "sha")?;
24 let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sha").unwrap();
26
27 fn read<'c>(ecx: &mut MiriInterpCx<'c>, reg: &OpTy<'c>) -> InterpResult<'c, [u32; 4]> {
28 let mut res = [0; 4];
29 for (i, dst) in res.iter_mut().rev().enumerate() {
32 let projected = &ecx.project_index(reg, i.try_into().unwrap())?;
33 *dst = ecx.read_scalar(projected)?.to_u32()?
34 }
35 interp_ok(res)
36 }
37
38 fn write<'c>(
39 ecx: &mut MiriInterpCx<'c>,
40 dest: &MPlaceTy<'c>,
41 val: [u32; 4],
42 ) -> InterpResult<'c, ()> {
43 for (i, part) in val.into_iter().rev().enumerate() {
46 let projected = &ecx.project_index(dest, i.try_into().unwrap())?;
47 ecx.write_scalar(Scalar::from_u32(part), projected)?;
48 }
49 interp_ok(())
50 }
51
52 match unprefixed_name {
53 "256rnds2" => {
55 let [a, b, k] = this.check_shim(abi, Conv::C, link_name, args)?;
56
57 let (a_reg, a_len) = this.project_to_simd(a)?;
58 let (b_reg, b_len) = this.project_to_simd(b)?;
59 let (k_reg, k_len) = this.project_to_simd(k)?;
60 let (dest, dest_len) = this.project_to_simd(dest)?;
61
62 assert_eq!(a_len, 4);
63 assert_eq!(b_len, 4);
64 assert_eq!(k_len, 4);
65 assert_eq!(dest_len, 4);
66
67 let a = read(this, &a_reg)?;
68 let b = read(this, &b_reg)?;
69 let k = read(this, &k_reg)?;
70
71 let result = sha256_digest_round_x2(a, b, k);
72 write(this, &dest, result)?;
73 }
74 "256msg1" => {
76 let [a, b] = this.check_shim(abi, Conv::C, link_name, args)?;
77
78 let (a_reg, a_len) = this.project_to_simd(a)?;
79 let (b_reg, b_len) = this.project_to_simd(b)?;
80 let (dest, dest_len) = this.project_to_simd(dest)?;
81
82 assert_eq!(a_len, 4);
83 assert_eq!(b_len, 4);
84 assert_eq!(dest_len, 4);
85
86 let a = read(this, &a_reg)?;
87 let b = read(this, &b_reg)?;
88
89 let result = sha256msg1(a, b);
90 write(this, &dest, result)?;
91 }
92 "256msg2" => {
94 let [a, b] = this.check_shim(abi, Conv::C, link_name, args)?;
95
96 let (a_reg, a_len) = this.project_to_simd(a)?;
97 let (b_reg, b_len) = this.project_to_simd(b)?;
98 let (dest, dest_len) = this.project_to_simd(dest)?;
99
100 assert_eq!(a_len, 4);
101 assert_eq!(b_len, 4);
102 assert_eq!(dest_len, 4);
103
104 let a = read(this, &a_reg)?;
105 let b = read(this, &b_reg)?;
106
107 let result = sha256msg2(a, b);
108 write(this, &dest, result)?;
109 }
110 _ => return interp_ok(EmulateItemResult::NotSupported),
111 }
112 interp_ok(EmulateItemResult::NeedsReturn)
113 }
114}
115
116#[inline(always)]
117fn shr(v: [u32; 4], o: u32) -> [u32; 4] {
118 [v[0] >> o, v[1] >> o, v[2] >> o, v[3] >> o]
119}
120
121#[inline(always)]
122fn shl(v: [u32; 4], o: u32) -> [u32; 4] {
123 [v[0] << o, v[1] << o, v[2] << o, v[3] << o]
124}
125
126#[inline(always)]
127fn or(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
128 [a[0] | b[0], a[1] | b[1], a[2] | b[2], a[3] | b[3]]
129}
130
131#[inline(always)]
132fn xor(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
133 [a[0] ^ b[0], a[1] ^ b[1], a[2] ^ b[2], a[3] ^ b[3]]
134}
135
136#[inline(always)]
137fn add(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
138 [
139 a[0].wrapping_add(b[0]),
140 a[1].wrapping_add(b[1]),
141 a[2].wrapping_add(b[2]),
142 a[3].wrapping_add(b[3]),
143 ]
144}
145
146fn sha256load(v2: [u32; 4], v3: [u32; 4]) -> [u32; 4] {
147 [v3[3], v2[0], v2[1], v2[2]]
148}
149
150fn sha256_digest_round_x2(cdgh: [u32; 4], abef: [u32; 4], wk: [u32; 4]) -> [u32; 4] {
151 macro_rules! big_sigma0 {
152 ($a:expr) => {
153 ($a.rotate_right(2) ^ $a.rotate_right(13) ^ $a.rotate_right(22))
154 };
155 }
156 macro_rules! big_sigma1 {
157 ($a:expr) => {
158 ($a.rotate_right(6) ^ $a.rotate_right(11) ^ $a.rotate_right(25))
159 };
160 }
161 macro_rules! bool3ary_202 {
162 ($a:expr, $b:expr, $c:expr) => {
163 $c ^ ($a & ($b ^ $c))
164 };
165 } macro_rules! bool3ary_232 {
167 ($a:expr, $b:expr, $c:expr) => {
168 ($a & $b) ^ ($a & $c) ^ ($b & $c)
169 };
170 } let [_, _, wk1, wk0] = wk;
173 let [a0, b0, e0, f0] = abef;
174 let [c0, d0, g0, h0] = cdgh;
175
176 let x0 =
178 big_sigma1!(e0).wrapping_add(bool3ary_202!(e0, f0, g0)).wrapping_add(wk0).wrapping_add(h0);
179 let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0));
180 let (a1, b1, c1, d1, e1, f1, g1, h1) =
181 (x0.wrapping_add(y0), a0, b0, c0, x0.wrapping_add(d0), e0, f0, g0);
182
183 let x1 =
185 big_sigma1!(e1).wrapping_add(bool3ary_202!(e1, f1, g1)).wrapping_add(wk1).wrapping_add(h1);
186 let y1 = big_sigma0!(a1).wrapping_add(bool3ary_232!(a1, b1, c1));
187 let (a2, b2, _, _, e2, f2, _, _) =
188 (x1.wrapping_add(y1), a1, b1, c1, x1.wrapping_add(d1), e1, f1, g1);
189
190 [a2, b2, e2, f2]
191}
192
193fn sha256msg1(v0: [u32; 4], v1: [u32; 4]) -> [u32; 4] {
194 #[inline]
196 fn sigma0x4(x: [u32; 4]) -> [u32; 4] {
197 let t1 = or(shr(x, 7), shl(x, 25));
198 let t2 = or(shr(x, 18), shl(x, 14));
199 let t3 = shr(x, 3);
200 xor(xor(t1, t2), t3)
201 }
202
203 add(v0, sigma0x4(sha256load(v0, v1)))
204}
205
206fn sha256msg2(v4: [u32; 4], v3: [u32; 4]) -> [u32; 4] {
207 macro_rules! sigma1 {
208 ($a:expr) => {
209 $a.rotate_right(17) ^ $a.rotate_right(19) ^ ($a >> 10)
210 };
211 }
212
213 let [x3, x2, x1, x0] = v4;
214 let [w15, w14, _, _] = v3;
215
216 let w16 = x0.wrapping_add(sigma1!(w14));
217 let w17 = x1.wrapping_add(sigma1!(w15));
218 let w18 = x2.wrapping_add(sigma1!(w16));
219 let w19 = x3.wrapping_add(sigma1!(w17));
220
221 [w19, w18, w17, w16]
222}