xref: /freebsd/contrib/llvm-project/compiler-rt/lib/builtins/arm/clzdi2.S (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric//===-- clzdi2.c - Implement __clzdi2 -------------------------------------===//
2*0b57cec5SDimitry Andric//
3*0b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric//
7*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric//
9*0b57cec5SDimitry Andric// This file implements count leading zeros for 64bit arguments.
10*0b57cec5SDimitry Andric//
11*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
12*0b57cec5SDimitry Andric
13*0b57cec5SDimitry Andric#include "../assembly.h"
14*0b57cec5SDimitry Andric
15*0b57cec5SDimitry Andric	.syntax unified
16*0b57cec5SDimitry Andric	.text
17*0b57cec5SDimitry Andric	DEFINE_CODE_STATE
18*0b57cec5SDimitry Andric
19*0b57cec5SDimitry Andric	.p2align	2
20*0b57cec5SDimitry AndricDEFINE_COMPILERRT_FUNCTION(__clzdi2)
21*0b57cec5SDimitry Andric#ifdef __ARM_FEATURE_CLZ
22*0b57cec5SDimitry Andric#ifdef __ARMEB__
23*0b57cec5SDimitry Andric	cmp	r0, 0
24*0b57cec5SDimitry Andric	itee ne
25*0b57cec5SDimitry Andric	clzne	r0, r0
26*0b57cec5SDimitry Andric	clzeq	r0, r1
27*0b57cec5SDimitry Andric	addeq	r0, r0, 32
28*0b57cec5SDimitry Andric#else
29*0b57cec5SDimitry Andric	cmp	r1, 0
30*0b57cec5SDimitry Andric	itee ne
31*0b57cec5SDimitry Andric	clzne	r0, r1
32*0b57cec5SDimitry Andric	clzeq	r0, r0
33*0b57cec5SDimitry Andric	addeq	r0, r0, 32
34*0b57cec5SDimitry Andric#endif
35*0b57cec5SDimitry Andric	JMP(lr)
36*0b57cec5SDimitry Andric#else
37*0b57cec5SDimitry Andric	// Assumption: n != 0
38*0b57cec5SDimitry Andric
39*0b57cec5SDimitry Andric	// r0: n
40*0b57cec5SDimitry Andric	// r1: upper half of n, overwritten after check
41*0b57cec5SDimitry Andric	// r1: count of leading zeros in n + 1
42*0b57cec5SDimitry Andric	// r2: scratch register for shifted r0
43*0b57cec5SDimitry Andric#ifdef __ARMEB__
44*0b57cec5SDimitry Andric	cmp	r0, 0
45*0b57cec5SDimitry Andric	moveq	r0, r1
46*0b57cec5SDimitry Andric#else
47*0b57cec5SDimitry Andric	cmp	r1, 0
48*0b57cec5SDimitry Andric	movne	r0, r1
49*0b57cec5SDimitry Andric#endif
50*0b57cec5SDimitry Andric	movne	r1, 1
51*0b57cec5SDimitry Andric	moveq	r1, 33
52*0b57cec5SDimitry Andric
53*0b57cec5SDimitry Andric	// Basic block:
54*0b57cec5SDimitry Andric	// if ((r0 >> SHIFT) == 0)
55*0b57cec5SDimitry Andric	//   r1 += SHIFT;
56*0b57cec5SDimitry Andric	// else
57*0b57cec5SDimitry Andric	//   r0 >>= SHIFT;
58*0b57cec5SDimitry Andric	// for descending powers of two as SHIFT.
59*0b57cec5SDimitry Andric#define BLOCK(shift) \
60*0b57cec5SDimitry Andric	lsrs	r2, r0, shift; \
61*0b57cec5SDimitry Andric	movne	r0, r2; \
62*0b57cec5SDimitry Andric	addeq	r1, shift \
63*0b57cec5SDimitry Andric
64*0b57cec5SDimitry Andric	BLOCK(16)
65*0b57cec5SDimitry Andric	BLOCK(8)
66*0b57cec5SDimitry Andric	BLOCK(4)
67*0b57cec5SDimitry Andric	BLOCK(2)
68*0b57cec5SDimitry Andric
69*0b57cec5SDimitry Andric	// The basic block invariants at this point are (r0 >> 2) == 0 and
70*0b57cec5SDimitry Andric	// r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
71*0b57cec5SDimitry Andric	//
72*0b57cec5SDimitry Andric	// r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
73*0b57cec5SDimitry Andric	// ---+----------------+----------------+------------+--------------
74*0b57cec5SDimitry Andric	// 1  | 1              | 0              | 0          | 1
75*0b57cec5SDimitry Andric	// 2  | 0              | 1              | -1         | 0
76*0b57cec5SDimitry Andric	// 3  | 0              | 1              | -1         | 0
77*0b57cec5SDimitry Andric	//
78*0b57cec5SDimitry Andric	// The r1's initial value of 1 compensates for the 1 here.
79*0b57cec5SDimitry Andric	sub	r0, r1, r0, lsr #1
80*0b57cec5SDimitry Andric
81*0b57cec5SDimitry Andric	JMP(lr)
82*0b57cec5SDimitry Andric#endif // __ARM_FEATURE_CLZ
83*0b57cec5SDimitry AndricEND_COMPILERRT_FUNCTION(__clzdi2)
84*0b57cec5SDimitry Andric
85*0b57cec5SDimitry AndricNO_EXEC_STACK_DIRECTIVE
86*0b57cec5SDimitry Andric
87