xref: /minix3/sys/external/bsd/compiler_rt/dist/lib/builtins/arm/clzdi2.S (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc/* ===-- clzdi2.c - Implement __clzdi2 -------------------------------------===
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 64bit 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
23*0a6a1f1dSLionel Sambuc	.p2align	2
24*0a6a1f1dSLionel SambucDEFINE_COMPILERRT_FUNCTION(__clzdi2)
25*0a6a1f1dSLionel Sambuc#ifdef __ARM_FEATURE_CLZ
26*0a6a1f1dSLionel Sambuc#ifdef __ARMEB__
27*0a6a1f1dSLionel Sambuc	cmp	r0, 0
28*0a6a1f1dSLionel Sambuc	itee ne
29*0a6a1f1dSLionel Sambuc	clzne	r0, r0
30*0a6a1f1dSLionel Sambuc	clzeq	r0, r1
31*0a6a1f1dSLionel Sambuc	addeq	r0, r0, 32
32*0a6a1f1dSLionel Sambuc#else
33*0a6a1f1dSLionel Sambuc	cmp	r1, 0
34*0a6a1f1dSLionel Sambuc	itee ne
35*0a6a1f1dSLionel Sambuc	clzne	r0, r1
36*0a6a1f1dSLionel Sambuc	clzeq	r0, r0
37*0a6a1f1dSLionel Sambuc	addeq	r0, r0, 32
38*0a6a1f1dSLionel Sambuc#endif
39*0a6a1f1dSLionel Sambuc	JMP(lr)
40*0a6a1f1dSLionel Sambuc#else
41*0a6a1f1dSLionel Sambuc	/* Assumption: n != 0 */
42*0a6a1f1dSLionel Sambuc
43*0a6a1f1dSLionel Sambuc	/*
44*0a6a1f1dSLionel Sambuc	 * r0: n
45*0a6a1f1dSLionel Sambuc	 * r1: upper half of n, overwritten after check
46*0a6a1f1dSLionel Sambuc	 * r1: count of leading zeros in n + 1
47*0a6a1f1dSLionel Sambuc	 * r2: scratch register for shifted r0
48*0a6a1f1dSLionel Sambuc	 */
49*0a6a1f1dSLionel Sambuc#ifdef __ARMEB__
50*0a6a1f1dSLionel Sambuc	cmp	r0, 0
51*0a6a1f1dSLionel Sambuc	moveq	r0, r1
52*0a6a1f1dSLionel Sambuc#else
53*0a6a1f1dSLionel Sambuc	cmp	r1, 0
54*0a6a1f1dSLionel Sambuc	movne	r0, r1
55*0a6a1f1dSLionel Sambuc#endif
56*0a6a1f1dSLionel Sambuc	movne	r1, 1
57*0a6a1f1dSLionel Sambuc	moveq	r1, 33
58*0a6a1f1dSLionel Sambuc
59*0a6a1f1dSLionel Sambuc	/*
60*0a6a1f1dSLionel Sambuc	 * Basic block:
61*0a6a1f1dSLionel Sambuc	 * if ((r0 >> SHIFT) == 0)
62*0a6a1f1dSLionel Sambuc	 *   r1 += SHIFT;
63*0a6a1f1dSLionel Sambuc	 * else
64*0a6a1f1dSLionel Sambuc	 *   r0 >>= SHIFT;
65*0a6a1f1dSLionel Sambuc	 * for descending powers of two as SHIFT.
66*0a6a1f1dSLionel Sambuc	 */
67*0a6a1f1dSLionel Sambuc#define BLOCK(shift) \
68*0a6a1f1dSLionel Sambuc	lsrs	r2, r0, shift; \
69*0a6a1f1dSLionel Sambuc	movne	r0, r2; \
70*0a6a1f1dSLionel Sambuc	addeq	r1, shift \
71*0a6a1f1dSLionel Sambuc
72*0a6a1f1dSLionel Sambuc	BLOCK(16)
73*0a6a1f1dSLionel Sambuc	BLOCK(8)
74*0a6a1f1dSLionel Sambuc	BLOCK(4)
75*0a6a1f1dSLionel Sambuc	BLOCK(2)
76*0a6a1f1dSLionel Sambuc
77*0a6a1f1dSLionel Sambuc	/*
78*0a6a1f1dSLionel Sambuc	 * The basic block invariants at this point are (r0 >> 2) == 0 and
79*0a6a1f1dSLionel Sambuc	 * r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
80*0a6a1f1dSLionel Sambuc	 *
81*0a6a1f1dSLionel Sambuc	 * r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
82*0a6a1f1dSLionel Sambuc	 * ---+----------------+----------------+------------+--------------
83*0a6a1f1dSLionel Sambuc	 * 1  | 1              | 0              | 0          | 1
84*0a6a1f1dSLionel Sambuc	 * 2  | 0              | 1              | -1         | 0
85*0a6a1f1dSLionel Sambuc	 * 3  | 0              | 1              | -1         | 0
86*0a6a1f1dSLionel Sambuc	 *
87*0a6a1f1dSLionel Sambuc	 * The r1's initial value of 1 compensates for the 1 here.
88*0a6a1f1dSLionel Sambuc	 */
89*0a6a1f1dSLionel Sambuc	sub	r0, r1, r0, lsr #1
90*0a6a1f1dSLionel Sambuc
91*0a6a1f1dSLionel Sambuc	JMP(lr)
92*0a6a1f1dSLionel Sambuc#endif // __ARM_FEATURE_CLZ
93*0a6a1f1dSLionel SambucEND_COMPILERRT_FUNCTION(__clzdi2)
94