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