aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/compiler-rt/lib/builtins/arm/clzsi2.S
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/compiler-rt/lib/builtins/arm/clzsi2.S')
-rw-r--r--contrib/llvm-project/compiler-rt/lib/builtins/arm/clzsi2.S66
1 files changed, 66 insertions, 0 deletions
diff --git a/contrib/llvm-project/compiler-rt/lib/builtins/arm/clzsi2.S b/contrib/llvm-project/compiler-rt/lib/builtins/arm/clzsi2.S
new file mode 100644
index 000000000000..5d86fe486edd
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/builtins/arm/clzsi2.S
@@ -0,0 +1,66 @@
+//===-- clzsi2.c - Implement __clzsi2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements count leading zeros for 32bit arguments.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+ .syntax unified
+ .text
+ DEFINE_CODE_STATE
+
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__clzsi2)
+#ifdef __ARM_FEATURE_CLZ
+ clz r0, r0
+ JMP(lr)
+#else
+ // Assumption: n != 0
+
+ // r0: n
+ // r1: count of leading zeros in n + 1
+ // r2: scratch register for shifted r0
+ mov r1, 1
+
+ // Basic block:
+ // if ((r0 >> SHIFT) == 0)
+ // r1 += SHIFT;
+ // else
+ // r0 >>= SHIFT;
+ // for descending powers of two as SHIFT.
+
+#define BLOCK(shift) \
+ lsrs r2, r0, shift; \
+ movne r0, r2; \
+ addeq r1, shift \
+
+ BLOCK(16)
+ BLOCK(8)
+ BLOCK(4)
+ BLOCK(2)
+
+ // The basic block invariants at this point are (r0 >> 2) == 0 and
+ // r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
+ //
+ // r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
+ // ---+----------------+----------------+------------+--------------
+ // 1 | 1 | 0 | 0 | 1
+ // 2 | 0 | 1 | -1 | 0
+ // 3 | 0 | 1 | -1 | 0
+ //
+ // The r1's initial value of 1 compensates for the 1 here.
+ sub r0, r1, r0, lsr #1
+
+ JMP(lr)
+#endif // __ARM_FEATURE_CLZ
+END_COMPILERRT_FUNCTION(__clzsi2)
+
+NO_EXEC_STACK_DIRECTIVE
+