Skip to content

Commit 8334a37

Browse files
committed
wip
1 parent ea0980f commit 8334a37

File tree

7 files changed

+362
-3
lines changed

7 files changed

+362
-3
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2683,6 +2683,7 @@ dependencies = [
26832683
name = "rustc_data_structures"
26842684
version = "0.0.0"
26852685
dependencies = [
2686+
"arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
26862687
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
26872688
"ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
26882689
"graphviz 0.0.0",

src/librustc_data_structures/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ path = "lib.rs"
1010
crate-type = ["dylib"]
1111

1212
[dependencies]
13+
arrayref = "0.3.5"
1314
ena = "0.13"
1415
log = "0.4"
1516
jobserver_crate = { version = "0.1", package = "jobserver" }

src/librustc_data_structures/ahash.rs

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
pub use rustc_hash::{FxHasher, FxHashMap, FxHashSet};
2+
use crate::convert::Convert;
3+
use std::hash::{Hasher};
4+
use std::slice;
5+
use std::mem;
6+
use std::sync::atomic::AtomicBool;
7+
use std::sync::atomic::Ordering::Relaxed;
8+
use arrayref::*;
9+
10+
const BUFFER_SIZE: usize = 1024;
11+
12+
pub struct BufferedHasher {
13+
cursor: usize,
14+
aes: AHasher,
15+
buffer: [u8; BUFFER_SIZE],
16+
}
17+
18+
impl ::std::fmt::Debug for BufferedHasher {
19+
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
20+
write!(f, "{:?} [{}]", self.aes, self.cursor)
21+
}
22+
}
23+
24+
#[inline(never)]
25+
#[no_mangle]
26+
#[target_feature(enable = "aes")]
27+
unsafe fn ahash_test(input: &[u8]) -> u64 {
28+
let mut a = AHasher::new_with_keys(67, 87);
29+
a.write(input);
30+
a.finish128().0
31+
}
32+
33+
#[inline(never)]
34+
#[no_mangle]
35+
fn ahash_test_one(b: &mut BufferedHasher, input: u64) {
36+
b.write_u64(input);
37+
}
38+
39+
static AES_ENABLED: AtomicBool = AtomicBool::new(true);
40+
41+
impl BufferedHasher {
42+
#[inline(always)]
43+
pub fn new() -> Self {
44+
BufferedHasher {
45+
aes: AHasher::new_with_keys(0, 0),
46+
cursor: 0,
47+
buffer: unsafe { std::mem::uninitialized() },
48+
}
49+
}
50+
51+
#[inline(always)]
52+
unsafe fn flush(&mut self) {
53+
self.aes.write(self.buffer.get_unchecked(0..self.cursor));
54+
}
55+
56+
#[inline(never)]
57+
#[cold]
58+
unsafe fn flush_cold(&mut self) {
59+
if likely!(AES_ENABLED.load(Relaxed)) {
60+
self.flush()
61+
} else {
62+
panic!("no aes");
63+
}
64+
}
65+
66+
#[inline(always)]
67+
fn short_write_gen<T>(&mut self, x: T) {
68+
let bytes = unsafe {
69+
slice::from_raw_parts(&x as *const T as *const u8, mem::size_of::<T>())
70+
};
71+
self.short_write(bytes);
72+
}
73+
74+
#[inline(always)]
75+
fn short_write(&mut self, data: &[u8]) {
76+
let mut cursor = self.cursor;
77+
let len = data.len();
78+
if unlikely!(cursor + len > BUFFER_SIZE) {
79+
unsafe { self.flush_cold() };
80+
cursor = 0;
81+
}
82+
unsafe {
83+
self.buffer.get_unchecked_mut(cursor..(cursor + len)).copy_from_slice(data);
84+
}
85+
self.cursor = cursor + len;
86+
}
87+
88+
#[inline(never)]
89+
#[target_feature(enable = "aes")]
90+
unsafe fn finish128_aes(mut self) -> (u64, u64) {
91+
self.flush();
92+
self.aes.finish128()
93+
}
94+
95+
#[inline]
96+
pub fn finish128(self) -> (u64, u64) {
97+
if likely!(AES_ENABLED.load(Relaxed)) {
98+
unsafe {
99+
self.finish128_aes()
100+
}
101+
} else {
102+
panic!("no aes");
103+
}
104+
}
105+
}
106+
107+
impl Hasher for BufferedHasher {
108+
#[inline]
109+
fn write_u8(&mut self, i: u8) {
110+
self.short_write_gen(i);
111+
}
112+
113+
#[inline]
114+
fn write_u16(&mut self, i: u16) {
115+
self.short_write_gen(i);
116+
}
117+
118+
#[inline]
119+
fn write_u32(&mut self, i: u32) {
120+
self.short_write_gen(i);
121+
}
122+
123+
#[inline]
124+
fn write_u64(&mut self, i: u64) {
125+
self.short_write_gen(i);
126+
}
127+
128+
#[inline]
129+
fn write_usize(&mut self, i: usize) {
130+
self.short_write_gen(i);
131+
}
132+
133+
#[inline]
134+
fn write_i8(&mut self, i: i8) {
135+
self.short_write_gen(i);
136+
}
137+
138+
#[inline]
139+
fn write_i16(&mut self, i: i16) {
140+
self.short_write_gen(i);
141+
}
142+
143+
#[inline]
144+
fn write_i32(&mut self, i: i32) {
145+
self.short_write_gen(i);
146+
}
147+
148+
#[inline]
149+
fn write_i64(&mut self, i: i64) {
150+
self.short_write_gen(i);
151+
}
152+
153+
#[inline]
154+
fn write_isize(&mut self, i: isize) {
155+
self.short_write_gen(i);
156+
}
157+
158+
#[inline]
159+
fn write(&mut self, data: &[u8]) {
160+
if likely!(data.len() < BUFFER_SIZE / 10) {
161+
self.short_write(data);
162+
} else {
163+
unsafe {
164+
self.aes.write(data);
165+
}
166+
}
167+
}
168+
169+
fn finish(&self) -> u64 {
170+
panic!("cannot provide valid 64 bit hashes")
171+
}
172+
}
173+
174+
///Just a simple bit pattern.
175+
const PAD : u128 = 0xF0E1_D2C3_B4A5_9687_7869_5A4B_3C2D_1E0F;
176+
177+
#[derive(Debug, Clone)]
178+
pub struct AHasher {
179+
buffer: [u64; 2],
180+
}
181+
182+
impl AHasher {
183+
#[inline]
184+
pub(crate) fn new_with_keys(key0: u64, key1: u64) -> AHasher {
185+
AHasher { buffer: [key0, key1] }
186+
}
187+
188+
#[inline]
189+
#[target_feature(enable = "aes")]
190+
unsafe fn write(&mut self, input: &[u8]) {
191+
let mut data = input;
192+
let length = data.len() as u64;
193+
//This will be scrambled by the first AES round in any branch.
194+
self.buffer[1] ^= length;
195+
//A 'binary search' on sizes reduces the number of comparisons.
196+
if data.len() >= 8 {
197+
if data.len() > 16 {
198+
if data.len() > 128 {
199+
let mut par_block: u128 = self.buffer.convert();
200+
while data.len() > 128 {
201+
let (b1, rest) = data.split_at(16);
202+
let b1: u128 = (*as_array!(b1, 16)).convert();
203+
par_block = aeshash(par_block, b1);
204+
data = rest;
205+
let (b2, rest) = data.split_at(16);
206+
let b2: u128 = (*as_array!(b2, 16)).convert();
207+
self.buffer = aeshash(self.buffer.convert(), b2).convert();
208+
data = rest;
209+
}
210+
self.buffer = aeshash(self.buffer.convert(), par_block).convert();
211+
}
212+
while data.len() > 32 {
213+
//len 33-128
214+
let (block, rest) = data.split_at(16);
215+
let block: u128 = (*as_array!(block, 16)).convert();
216+
self.buffer = aeshash(self.buffer.convert(),block).convert();
217+
data = rest;
218+
}
219+
//len 17-32
220+
let block = (*array_ref!(data, 0, 16)).convert();
221+
self.buffer = aeshash(self.buffer.convert(),block).convert();
222+
let block = (*array_ref!(data, data.len()-16, 16)).convert();
223+
self.buffer = aeshash(self.buffer.convert(),block).convert();
224+
} else {
225+
//len 8-16
226+
let block: [u64; 2] = [(*array_ref!(data, 0, 8)).convert(),
227+
(*array_ref!(data, data.len()-8, 8)).convert()];
228+
self.buffer = aeshash(self.buffer.convert(),block.convert()).convert();
229+
}
230+
} else {
231+
if data.len() >= 2 {
232+
if data.len() >= 4 {
233+
//len 4-7
234+
let block: [u32; 2] = [(*array_ref!(data, 0, 4)).convert(),
235+
(*array_ref!(data, data.len()-4, 4)).convert()];
236+
let block: [u64;2] = [block[1] as u64, block[0] as u64];
237+
self.buffer = aeshash(self.buffer.convert(),block.convert()).convert()
238+
} else {
239+
//len 2-3
240+
let block: [u16; 2] = [(*array_ref!(data, 0, 2)).convert(),
241+
(*array_ref!(data, data.len()-2, 2)).convert()];
242+
let block: u32 = block.convert();
243+
self.buffer = aeshash(self.buffer.convert(), block as u128).convert();
244+
}
245+
} else {
246+
if data.len() > 0 {
247+
//len 1
248+
self.buffer = aeshash(self.buffer.convert(), data[0] as u128).convert();
249+
}
250+
}
251+
}
252+
}
253+
#[inline]
254+
#[target_feature(enable = "aes")]
255+
unsafe fn finish128(self) -> (u64, u64) {
256+
let result: [u64; 2] = aeshash(aeshash(self.buffer.convert(), PAD), PAD).convert();
257+
(result[0], result[1])
258+
}
259+
}
260+
261+
#[inline]
262+
#[target_feature(enable = "aes")]
263+
unsafe fn aeshash(value: u128, xor: u128) -> u128 {
264+
use std::mem::transmute;
265+
#[cfg(target_arch = "x86")]
266+
use core::arch::x86::*;
267+
#[cfg(target_arch = "x86_64")]
268+
use std::arch::x86_64::*;
269+
let value = transmute(value);
270+
transmute(_mm_aesdec_si128(value, transmute(xor)))
271+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use std::mem::transmute;
2+
3+
pub(crate) trait Convert<To> {
4+
fn convert(self) -> To;
5+
fn convert_ref(&self) -> &To;
6+
fn convert_mut_ref(&mut self) -> &mut To;
7+
}
8+
macro_rules! convert {
9+
($from:ty, $to:ty) => {
10+
impl Convert<$to> for $from {
11+
#[inline(always)]
12+
fn convert(self) -> $to {
13+
unsafe { transmute(self) }
14+
}
15+
#[inline(always)]
16+
fn convert_ref(&self) -> &$to {
17+
unsafe { transmute(self) }
18+
}
19+
#[inline(always)]
20+
fn convert_mut_ref(&mut self) -> &mut $to {
21+
unsafe { transmute(self) }
22+
}
23+
}
24+
impl Convert<$from> for $to {
25+
#[inline(always)]
26+
fn convert(self) -> $from {
27+
unsafe { transmute(self) }
28+
}
29+
#[inline(always)]
30+
fn convert_ref(&self) -> &$from {
31+
unsafe { transmute(self) }
32+
}
33+
#[inline(always)]
34+
fn convert_mut_ref(&mut self) -> &mut $from {
35+
unsafe { transmute(self) }
36+
}
37+
}
38+
};
39+
}
40+
convert!(u128, [u64; 2]);
41+
convert!(u128, [u32; 4]);
42+
convert!(u128, [u16; 8]);
43+
convert!(u128, [u8; 16]);
44+
convert!([u64; 2], [u32; 4]);
45+
convert!([u64; 2], [u16; 8]);
46+
convert!([u64; 2], [u8; 16]);
47+
convert!([u32; 4], [u16; 8]);
48+
convert!([u32; 4], [u8; 16]);
49+
convert!([u16; 8], [u8; 16]);
50+
convert!(u64, [u32; 2]);
51+
convert!(u64, [u16; 4]);
52+
convert!(u64, [u8; 8]);
53+
convert!([u32; 2], [u16; 4]);
54+
convert!([u32; 2], [u8; 8]);
55+
convert!(u32, [u16; 2]);
56+
convert!(u32, [u8; 4]);
57+
convert!([u16; 2], [u8; 4]);
58+
convert!(u16, [u8; 2]);
59+
60+
convert!([f64; 2], [u8; 16]);
61+
convert!([f32; 4], [u8; 16]);
62+
convert!(f64, [u8; 8]);
63+
convert!([f32; 2], [u8; 8]);
64+
convert!(f32, [u8; 4]);
65+
66+
67+
68+
macro_rules! as_array {
69+
($input:expr, $len:expr) => {{
70+
{
71+
#[inline]
72+
fn as_array<T>(slice: &[T]) -> &[T; $len] {
73+
assert_eq!(slice.len(), $len);
74+
unsafe {
75+
&*(slice.as_ptr() as *const [_; $len])
76+
}
77+
}
78+
as_array($input)
79+
}
80+
}}
81+
}

src/librustc_data_structures/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ macro_rules! unlikely {
6969
}
7070
}
7171

72+
#[macro_use]
73+
pub mod convert;
74+
pub mod ahash;
7275
pub mod macros;
7376
pub mod svh;
7477
pub mod base_n;

0 commit comments

Comments
 (0)