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