Prechádzať zdrojové kódy

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.
Christopher Haster 7 rokov pred
rodič
commit
4f08424b51
1 zmenil súbory, kde vykonal 25 pridanie a 4 odobranie
  1. 25 4
      lfs_util.h

+ 25 - 4
lfs_util.h

@@ -33,16 +33,37 @@ static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
     return (a < b) ? a : b;
 }
 
-static inline uint32_t lfs_ctz(uint32_t a) {
-    return __builtin_ctz(a);
-}
-
 static inline uint32_t lfs_npw2(uint32_t a) {
+#if defined(__GNUC__) || defined(__CC_ARM)
     return 32 - __builtin_clz(a-1);
+#else
+    uint32_t r = 0;
+    uint32_t s;
+    a -= 1;
+    s = (a > 0xffff) << 4; a >>= s; r |= s;
+    s = (a > 0xff  ) << 3; a >>= s; r |= s;
+    s = (a > 0xf   ) << 2; a >>= s; r |= s;
+    s = (a > 0x3   ) << 1; a >>= s; r |= s;
+    return (r | (a >> 1)) + 1;
+#endif
+}
+
+static inline uint32_t lfs_ctz(uint32_t a) {
+#if defined(__GNUC__)
+    return __builtin_ctz(a);
+#else
+    return lfs_npw2((a & -a) + 1) - 1;
+#endif
 }
 
 static inline uint32_t lfs_popc(uint32_t a) {
+#if defined(__GNUC__) || defined(__CC_ARM)
     return __builtin_popcount(a);
+#else
+    a = a - ((a >> 1) & 0x55555555);
+    a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
+    return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
+#endif
 }
 
 static inline int lfs_scmp(uint32_t a, uint32_t b) {