xref: /minix3/sys/external/bsd/compiler_rt/dist/lib/builtins/arm/clzsi2.S (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc/* ===-- clzsi2.c - Implement __clzsi2 -------------------------------------===
2*0a6a1f1dSLionel Sambuc *
3*0a6a1f1dSLionel Sambuc *               The LLVM Compiler Infrastructure
4*0a6a1f1dSLionel Sambuc *
5*0a6a1f1dSLionel Sambuc * This file is dual licensed under the MIT and the University of Illinois Open
6*0a6a1f1dSLionel Sambuc * Source Licenses. See LICENSE.TXT for details.
7*0a6a1f1dSLionel Sambuc *
8*0a6a1f1dSLionel Sambuc * ===----------------------------------------------------------------------===
9*0a6a1f1dSLionel Sambuc *
10*0a6a1f1dSLionel Sambuc * This file implements count leading zeros for 32bit arguments.
11*0a6a1f1dSLionel Sambuc *
12*0a6a1f1dSLionel Sambuc * ===----------------------------------------------------------------------===
13*0a6a1f1dSLionel Sambuc */
14*0a6a1f1dSLionel Sambuc#include "../assembly.h"
15*0a6a1f1dSLionel Sambuc
16*0a6a1f1dSLionel Sambuc	.syntax unified
17*0a6a1f1dSLionel Sambuc	.text
18*0a6a1f1dSLionel Sambuc#if __ARM_ARCH_ISA_THUMB == 2
19*0a6a1f1dSLionel Sambuc	.thumb
20*0a6a1f1dSLionel Sambuc#endif
21*0a6a1f1dSLionel Sambuc
22*0a6a1f1dSLionel Sambuc	.p2align	2
23*0a6a1f1dSLionel SambucDEFINE_COMPILERRT_FUNCTION(__clzsi2)
24*0a6a1f1dSLionel Sambuc#ifdef __ARM_FEATURE_CLZ
25*0a6a1f1dSLionel Sambuc	clz	r0, r0
26*0a6a1f1dSLionel Sambuc	JMP(lr)
27*0a6a1f1dSLionel Sambuc#else
28*0a6a1f1dSLionel Sambuc	/* Assumption: n != 0 */
29*0a6a1f1dSLionel Sambuc
30*0a6a1f1dSLionel Sambuc	/*
31*0a6a1f1dSLionel Sambuc	 * r0: n
32*0a6a1f1dSLionel Sambuc	 * r1: count of leading zeros in n + 1
33*0a6a1f1dSLionel Sambuc	 * r2: scratch register for shifted r0
34*0a6a1f1dSLionel Sambuc	 */
35*0a6a1f1dSLionel Sambuc	mov	r1, 1
36*0a6a1f1dSLionel Sambuc
37*0a6a1f1dSLionel Sambuc	/*
38*0a6a1f1dSLionel Sambuc	 * Basic block:
39*0a6a1f1dSLionel Sambuc	 * if ((r0 >> SHIFT) == 0)
40*0a6a1f1dSLionel Sambuc	 *   r1 += SHIFT;
41*0a6a1f1dSLionel Sambuc	 * else
42*0a6a1f1dSLionel Sambuc	 *   r0 >>= SHIFT;
43*0a6a1f1dSLionel Sambuc	 * for descending powers of two as SHIFT.
44*0a6a1f1dSLionel Sambuc	 */
45*0a6a1f1dSLionel Sambuc
46*0a6a1f1dSLionel Sambuc#define BLOCK(shift) \
47*0a6a1f1dSLionel Sambuc	lsrs	r2, r0, shift; \
48*0a6a1f1dSLionel Sambuc	movne	r0, r2; \
49*0a6a1f1dSLionel Sambuc	addeq	r1, shift \
50*0a6a1f1dSLionel Sambuc
51*0a6a1f1dSLionel Sambuc	BLOCK(16)
52*0a6a1f1dSLionel Sambuc	BLOCK(8)
53*0a6a1f1dSLionel Sambuc	BLOCK(4)
54*0a6a1f1dSLionel Sambuc	BLOCK(2)
55*0a6a1f1dSLionel Sambuc
56*0a6a1f1dSLionel Sambuc	/*
57*0a6a1f1dSLionel Sambuc	 * The basic block invariants at this point are (r0 >> 2) == 0 and
58*0a6a1f1dSLionel Sambuc	 * r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
59*0a6a1f1dSLionel Sambuc	 *
60*0a6a1f1dSLionel Sambuc	 * r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
61*0a6a1f1dSLionel Sambuc	 * ---+----------------+----------------+------------+--------------
62*0a6a1f1dSLionel Sambuc	 * 1  | 1              | 0              | 0          | 1
63*0a6a1f1dSLionel Sambuc	 * 2  | 0              | 1              | -1         | 0
64*0a6a1f1dSLionel Sambuc	 * 3  | 0              | 1              | -1         | 0
65*0a6a1f1dSLionel Sambuc	 *
66*0a6a1f1dSLionel Sambuc	 * The r1's initial value of 1 compensates for the 1 here.
67*0a6a1f1dSLionel Sambuc	 */
68*0a6a1f1dSLionel Sambuc	sub	r0, r1, r0, lsr #1
69*0a6a1f1dSLionel Sambuc
70*0a6a1f1dSLionel Sambuc	JMP(lr)
71*0a6a1f1dSLionel Sambuc#endif // __ARM_FEATURE_CLZ
72*0a6a1f1dSLionel SambucEND_COMPILERRT_FUNCTION(__clzsi2)
73