Skip to content

Commit 3884f5f

Browse files
committed
auto merge of #16965 : huonw/rust/isaac-oob--, r=alexcrichton
rand: inform the optimiser that indexing is never out-of-bounds. This uses a bitwise mask to ensure that there's no bounds checking for the array accesses when generating the next random number. This isn't costless, but the single instruction is nothing compared to the branch. A `debug_assert` for "bounds check" is preserved to ensure that refactoring doesn't accidentally break it (i.e. create values of `cnt` that are out of bounds with the masking causing it to silently wrap- around). Before: test test::rand_isaac ... bench: 990 ns/iter (+/- 24) = 808 MB/s test test::rand_isaac64 ... bench: 614 ns/iter (+/- 25) = 1302 MB/s After: test test::rand_isaac ... bench: 877 ns/iter (+/- 134) = 912 MB/s test test::rand_isaac64 ... bench: 470 ns/iter (+/- 30) = 1702 MB/s (It also removes the unsafe code in Isaac64Rng.next_u64, with a *gain* in performance; today is a good day.)
2 parents 7ab58f6 + cc6a487 commit 3884f5f

File tree

1 file changed

+18
-2
lines changed

1 file changed

+18
-2
lines changed

src/librand/isaac.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,19 @@ impl Rng for IsaacRng {
185185
self.isaac();
186186
}
187187
self.cnt -= 1;
188-
self.rsl[self.cnt as uint]
188+
189+
// self.cnt is at most RAND_SIZE, but that is before the
190+
// subtraction above. We want to index without bounds
191+
// checking, but this could lead to incorrect code if someone
192+
// misrefactors, so we check, sometimes.
193+
//
194+
// (Changes here should be reflected in Isaac64Rng.next_u64.)
195+
debug_assert!(self.cnt < RAND_SIZE);
196+
197+
// (the % is cheaply telling the optimiser that we're always
198+
// in bounds, without unsafe. NB. this is a power of two, so
199+
// it optimises to a bitwise mask).
200+
self.rsl[(self.cnt % RAND_SIZE) as uint]
189201
}
190202
}
191203

@@ -416,7 +428,11 @@ impl Rng for Isaac64Rng {
416428
self.isaac64();
417429
}
418430
self.cnt -= 1;
419-
unsafe { *self.rsl.unsafe_get(self.cnt) }
431+
432+
// See corresponding location in IsaacRng.next_u32 for
433+
// explanation.
434+
debug_assert!(self.cnt < RAND_SIZE_64)
435+
self.rsl[(self.cnt % RAND_SIZE_64) as uint]
420436
}
421437
}
422438

0 commit comments

Comments
 (0)