Skip to content

Commit 4f08424

Browse files
committed
Added software implementations of bitwise instructions
This helps significantly with supporting different compilers. Intrinsics for different compilers can be added as they are found. Note that for ARMCC, __builtin_ctz is not used. This was the result of a strange issue where ARMCC only emits __builtin_ctz when passed the --gnu flag, but __builtin_clz and __builtin_popcount are always emitted. This isn't a big problem since the ARM instruction set doesn't have a ctz instruction, and the npw2 based implementation is one of the most efficient. Also note that for littefs's purposes, we consider ctz(0) to be undefined. This lets us save a branch in the software lfs_ctz implementation.
1 parent 59ce49f commit 4f08424

File tree

1 file changed

+25
-4
lines changed

1 file changed

+25
-4
lines changed

lfs_util.h

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,37 @@ static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
3333
return (a < b) ? a : b;
3434
}
3535

36-
static inline uint32_t lfs_ctz(uint32_t a) {
37-
return __builtin_ctz(a);
38-
}
39-
4036
static inline uint32_t lfs_npw2(uint32_t a) {
37+
#if defined(__GNUC__) || defined(__CC_ARM)
4138
return 32 - __builtin_clz(a-1);
39+
#else
40+
uint32_t r = 0;
41+
uint32_t s;
42+
a -= 1;
43+
s = (a > 0xffff) << 4; a >>= s; r |= s;
44+
s = (a > 0xff ) << 3; a >>= s; r |= s;
45+
s = (a > 0xf ) << 2; a >>= s; r |= s;
46+
s = (a > 0x3 ) << 1; a >>= s; r |= s;
47+
return (r | (a >> 1)) + 1;
48+
#endif
49+
}
50+
51+
static inline uint32_t lfs_ctz(uint32_t a) {
52+
#if defined(__GNUC__)
53+
return __builtin_ctz(a);
54+
#else
55+
return lfs_npw2((a & -a) + 1) - 1;
56+
#endif
4257
}
4358

4459
static inline uint32_t lfs_popc(uint32_t a) {
60+
#if defined(__GNUC__) || defined(__CC_ARM)
4561
return __builtin_popcount(a);
62+
#else
63+
a = a - ((a >> 1) & 0x55555555);
64+
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
65+
return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
66+
#endif
4667
}
4768

4869
static inline int lfs_scmp(uint32_t a, uint32_t b) {

0 commit comments

Comments
 (0)