Make rolN / rorN safe for all counts.

The current version invokes undefined behavior when the count is negative, zero, or equal to or greater than the width of the operand.  The new version masks the count to avoid these situations.  Although branchless, it is relatively inefficient if the compiler does not recognize it and translate it to a rol or ror instruction.  Empirical tests show that both clang and gcc get it right for constant counts, and recent versions of clang (but not gcc) get it right for variable counts as well.  Note that our current code base has no instances of rolN / rorN with a variable count.
This commit is contained in:
Dag-Erling Smørgrav 2017-03-22 16:50:01 +01:00
parent c556bc0aa8
commit d2d16d26da

View file

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2012 The University of Oslo
* Copyright (c) 2012-2016 Dag-Erling Smørgrav
* Copyright (c) 2012-2017 Dag-Erling Smørgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -40,11 +40,11 @@ CRYB_BEGIN
#define CRYB_ROL_ROR(N) \
static inline uint##N##_t rol##N(uint##N##_t i, int n) \
{ \
return (i << n | i >> (N - n)); \
return (i << (n & (N - 1)) | i >> (-n & (N - 1))); \
} \
static inline uint##N##_t ror##N(uint##N##_t i, int n) \
{ \
return (i << (N - n) | i >> n); \
return (i << (-n & (N - 1)) | i >> (n & (N - 1))); \
}
CRYB_ROL_ROR(8);