xref: /openbsd-src/gnu/llvm/compiler-rt/lib/builtins/arm/clzsi2.S (revision 3cab2bb3f667058bece8e38b12449a63a9d73c4b)
1*3cab2bb3Spatrick//===-- clzsi2.c - Implement __clzsi2 -------------------------------------===//
2*3cab2bb3Spatrick//
3*3cab2bb3Spatrick// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*3cab2bb3Spatrick// See https://llvm.org/LICENSE.txt for license information.
5*3cab2bb3Spatrick// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*3cab2bb3Spatrick//
7*3cab2bb3Spatrick//===----------------------------------------------------------------------===//
8*3cab2bb3Spatrick//
9*3cab2bb3Spatrick// This file implements count leading zeros for 32bit arguments.
10*3cab2bb3Spatrick//
11*3cab2bb3Spatrick//===----------------------------------------------------------------------===//
12*3cab2bb3Spatrick
13*3cab2bb3Spatrick#include "../assembly.h"
14*3cab2bb3Spatrick
15*3cab2bb3Spatrick	.syntax unified
16*3cab2bb3Spatrick	.text
17*3cab2bb3Spatrick	DEFINE_CODE_STATE
18*3cab2bb3Spatrick
19*3cab2bb3Spatrick	.p2align	2
20*3cab2bb3SpatrickDEFINE_COMPILERRT_FUNCTION(__clzsi2)
21*3cab2bb3Spatrick#ifdef __ARM_FEATURE_CLZ
22*3cab2bb3Spatrick	clz	r0, r0
23*3cab2bb3Spatrick	JMP(lr)
24*3cab2bb3Spatrick#else
25*3cab2bb3Spatrick	// Assumption: n != 0
26*3cab2bb3Spatrick
27*3cab2bb3Spatrick	// r0: n
28*3cab2bb3Spatrick	// r1: count of leading zeros in n + 1
29*3cab2bb3Spatrick	// r2: scratch register for shifted r0
30*3cab2bb3Spatrick	mov	r1, 1
31*3cab2bb3Spatrick
32*3cab2bb3Spatrick	// Basic block:
33*3cab2bb3Spatrick	// if ((r0 >> SHIFT) == 0)
34*3cab2bb3Spatrick	//   r1 += SHIFT;
35*3cab2bb3Spatrick	// else
36*3cab2bb3Spatrick	//   r0 >>= SHIFT;
37*3cab2bb3Spatrick	// for descending powers of two as SHIFT.
38*3cab2bb3Spatrick
39*3cab2bb3Spatrick#define BLOCK(shift) \
40*3cab2bb3Spatrick	lsrs	r2, r0, shift; \
41*3cab2bb3Spatrick	movne	r0, r2; \
42*3cab2bb3Spatrick	addeq	r1, shift \
43*3cab2bb3Spatrick
44*3cab2bb3Spatrick	BLOCK(16)
45*3cab2bb3Spatrick	BLOCK(8)
46*3cab2bb3Spatrick	BLOCK(4)
47*3cab2bb3Spatrick	BLOCK(2)
48*3cab2bb3Spatrick
49*3cab2bb3Spatrick	// The basic block invariants at this point are (r0 >> 2) == 0 and
50*3cab2bb3Spatrick	// r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
51*3cab2bb3Spatrick	//
52*3cab2bb3Spatrick	// r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
53*3cab2bb3Spatrick	// ---+----------------+----------------+------------+--------------
54*3cab2bb3Spatrick	// 1  | 1              | 0              | 0          | 1
55*3cab2bb3Spatrick	// 2  | 0              | 1              | -1         | 0
56*3cab2bb3Spatrick	// 3  | 0              | 1              | -1         | 0
57*3cab2bb3Spatrick	//
58*3cab2bb3Spatrick	// The r1's initial value of 1 compensates for the 1 here.
59*3cab2bb3Spatrick	sub	r0, r1, r0, lsr #1
60*3cab2bb3Spatrick
61*3cab2bb3Spatrick	JMP(lr)
62*3cab2bb3Spatrick#endif // __ARM_FEATURE_CLZ
63*3cab2bb3SpatrickEND_COMPILERRT_FUNCTION(__clzsi2)
64*3cab2bb3Spatrick
65*3cab2bb3SpatrickNO_EXEC_STACK_DIRECTIVE
66*3cab2bb3Spatrick
67