xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/builtins/arm/clzsi2.S (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric//===-- clzsi2.c - Implement __clzsi2 -------------------------------------===//
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 32bit 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(__clzsi2)
21*0b57cec5SDimitry Andric#ifdef __ARM_FEATURE_CLZ
22*0b57cec5SDimitry Andric	clz	r0, r0
23*0b57cec5SDimitry Andric	JMP(lr)
24*0b57cec5SDimitry Andric#else
25*0b57cec5SDimitry Andric	// Assumption: n != 0
26*0b57cec5SDimitry Andric
27*0b57cec5SDimitry Andric	// r0: n
28*0b57cec5SDimitry Andric	// r1: count of leading zeros in n + 1
29*0b57cec5SDimitry Andric	// r2: scratch register for shifted r0
30*0b57cec5SDimitry Andric	mov	r1, 1
31*0b57cec5SDimitry Andric
32*0b57cec5SDimitry Andric	// Basic block:
33*0b57cec5SDimitry Andric	// if ((r0 >> SHIFT) == 0)
34*0b57cec5SDimitry Andric	//   r1 += SHIFT;
35*0b57cec5SDimitry Andric	// else
36*0b57cec5SDimitry Andric	//   r0 >>= SHIFT;
37*0b57cec5SDimitry Andric	// for descending powers of two as SHIFT.
38*0b57cec5SDimitry Andric
39*0b57cec5SDimitry Andric#define BLOCK(shift) \
40*0b57cec5SDimitry Andric	lsrs	r2, r0, shift; \
41*0b57cec5SDimitry Andric	movne	r0, r2; \
42*0b57cec5SDimitry Andric	addeq	r1, shift \
43*0b57cec5SDimitry Andric
44*0b57cec5SDimitry Andric	BLOCK(16)
45*0b57cec5SDimitry Andric	BLOCK(8)
46*0b57cec5SDimitry Andric	BLOCK(4)
47*0b57cec5SDimitry Andric	BLOCK(2)
48*0b57cec5SDimitry Andric
49*0b57cec5SDimitry Andric	// The basic block invariants at this point are (r0 >> 2) == 0 and
50*0b57cec5SDimitry Andric	// r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
51*0b57cec5SDimitry Andric	//
52*0b57cec5SDimitry Andric	// r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
53*0b57cec5SDimitry Andric	// ---+----------------+----------------+------------+--------------
54*0b57cec5SDimitry Andric	// 1  | 1              | 0              | 0          | 1
55*0b57cec5SDimitry Andric	// 2  | 0              | 1              | -1         | 0
56*0b57cec5SDimitry Andric	// 3  | 0              | 1              | -1         | 0
57*0b57cec5SDimitry Andric	//
58*0b57cec5SDimitry Andric	// The r1's initial value of 1 compensates for the 1 here.
59*0b57cec5SDimitry Andric	sub	r0, r1, r0, lsr #1
60*0b57cec5SDimitry Andric
61*0b57cec5SDimitry Andric	JMP(lr)
62*0b57cec5SDimitry Andric#endif // __ARM_FEATURE_CLZ
63*0b57cec5SDimitry AndricEND_COMPILERRT_FUNCTION(__clzsi2)
64*0b57cec5SDimitry Andric
65*0b57cec5SDimitry AndricNO_EXEC_STACK_DIRECTIVE
66*0b57cec5SDimitry Andric
67