17db96d56Sopenharmony_ci/*
27db96d56Sopenharmony_ci * Copyright (c) 2008-2020 Stefan Krah. All rights reserved.
37db96d56Sopenharmony_ci *
47db96d56Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
57db96d56Sopenharmony_ci * modification, are permitted provided that the following conditions
67db96d56Sopenharmony_ci * are met:
77db96d56Sopenharmony_ci *
87db96d56Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
97db96d56Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
107db96d56Sopenharmony_ci *
117db96d56Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
127db96d56Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
137db96d56Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
147db96d56Sopenharmony_ci *
157db96d56Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
167db96d56Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
177db96d56Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
187db96d56Sopenharmony_ci * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
197db96d56Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
207db96d56Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
217db96d56Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
227db96d56Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
237db96d56Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
247db96d56Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
257db96d56Sopenharmony_ci * SUCH DAMAGE.
267db96d56Sopenharmony_ci */
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci#ifndef LIBMPDEC_BITS_H_
307db96d56Sopenharmony_ci#define LIBMPDEC_BITS_H_
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci#include "mpdecimal.h"
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ci/* Check if n is a power of 2. */
377db96d56Sopenharmony_cistatic inline int
387db96d56Sopenharmony_ciispower2(mpd_size_t n)
397db96d56Sopenharmony_ci{
407db96d56Sopenharmony_ci    return n != 0 && (n & (n-1)) == 0;
417db96d56Sopenharmony_ci}
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_ci#if defined(ANSI)
447db96d56Sopenharmony_ci/*
457db96d56Sopenharmony_ci * Return the most significant bit position of n from 0 to 31 (63).
467db96d56Sopenharmony_ci * Assumptions: n != 0.
477db96d56Sopenharmony_ci */
487db96d56Sopenharmony_cistatic inline int
497db96d56Sopenharmony_cimpd_bsr(mpd_size_t n)
507db96d56Sopenharmony_ci{
517db96d56Sopenharmony_ci    int pos = 0;
527db96d56Sopenharmony_ci    mpd_size_t tmp;
537db96d56Sopenharmony_ci
547db96d56Sopenharmony_ci#ifdef CONFIG_64
557db96d56Sopenharmony_ci    tmp = n >> 32;
567db96d56Sopenharmony_ci    if (tmp != 0) { n = tmp; pos += 32; }
577db96d56Sopenharmony_ci#endif
587db96d56Sopenharmony_ci    tmp = n >> 16;
597db96d56Sopenharmony_ci    if (tmp != 0) { n = tmp; pos += 16; }
607db96d56Sopenharmony_ci    tmp = n >> 8;
617db96d56Sopenharmony_ci    if (tmp != 0) { n = tmp; pos += 8; }
627db96d56Sopenharmony_ci    tmp = n >> 4;
637db96d56Sopenharmony_ci    if (tmp != 0) { n = tmp; pos += 4; }
647db96d56Sopenharmony_ci    tmp = n >> 2;
657db96d56Sopenharmony_ci    if (tmp != 0) { n = tmp; pos += 2; }
667db96d56Sopenharmony_ci    tmp = n >> 1;
677db96d56Sopenharmony_ci    if (tmp != 0) { n = tmp; pos += 1; }
687db96d56Sopenharmony_ci
697db96d56Sopenharmony_ci    return pos + (int)n - 1;
707db96d56Sopenharmony_ci}
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_ci/*
737db96d56Sopenharmony_ci * Return the least significant bit position of n from 0 to 31 (63).
747db96d56Sopenharmony_ci * Assumptions: n != 0.
757db96d56Sopenharmony_ci */
767db96d56Sopenharmony_cistatic inline int
777db96d56Sopenharmony_cimpd_bsf(mpd_size_t n)
787db96d56Sopenharmony_ci{
797db96d56Sopenharmony_ci    int pos;
807db96d56Sopenharmony_ci
817db96d56Sopenharmony_ci#ifdef CONFIG_64
827db96d56Sopenharmony_ci    pos = 63;
837db96d56Sopenharmony_ci    if (n & 0x00000000FFFFFFFFULL) { pos -= 32; } else { n >>= 32; }
847db96d56Sopenharmony_ci    if (n & 0x000000000000FFFFULL) { pos -= 16; } else { n >>= 16; }
857db96d56Sopenharmony_ci    if (n & 0x00000000000000FFULL) { pos -=  8; } else { n >>=  8; }
867db96d56Sopenharmony_ci    if (n & 0x000000000000000FULL) { pos -=  4; } else { n >>=  4; }
877db96d56Sopenharmony_ci    if (n & 0x0000000000000003ULL) { pos -=  2; } else { n >>=  2; }
887db96d56Sopenharmony_ci    if (n & 0x0000000000000001ULL) { pos -=  1; }
897db96d56Sopenharmony_ci#else
907db96d56Sopenharmony_ci    pos = 31;
917db96d56Sopenharmony_ci    if (n & 0x000000000000FFFFUL) { pos -= 16; } else { n >>= 16; }
927db96d56Sopenharmony_ci    if (n & 0x00000000000000FFUL) { pos -=  8; } else { n >>=  8; }
937db96d56Sopenharmony_ci    if (n & 0x000000000000000FUL) { pos -=  4; } else { n >>=  4; }
947db96d56Sopenharmony_ci    if (n & 0x0000000000000003UL) { pos -=  2; } else { n >>=  2; }
957db96d56Sopenharmony_ci    if (n & 0x0000000000000001UL) { pos -=  1; }
967db96d56Sopenharmony_ci#endif
977db96d56Sopenharmony_ci    return pos;
987db96d56Sopenharmony_ci}
997db96d56Sopenharmony_ci/* END ANSI */
1007db96d56Sopenharmony_ci
1017db96d56Sopenharmony_ci#elif defined(ASM)
1027db96d56Sopenharmony_ci/*
1037db96d56Sopenharmony_ci * Bit scan reverse. Assumptions: a != 0.
1047db96d56Sopenharmony_ci */
1057db96d56Sopenharmony_cistatic inline int
1067db96d56Sopenharmony_cimpd_bsr(mpd_size_t a)
1077db96d56Sopenharmony_ci{
1087db96d56Sopenharmony_ci    mpd_size_t retval;
1097db96d56Sopenharmony_ci
1107db96d56Sopenharmony_ci    __asm__ (
1117db96d56Sopenharmony_ci#ifdef CONFIG_64
1127db96d56Sopenharmony_ci        "bsrq %1, %0\n\t"
1137db96d56Sopenharmony_ci#else
1147db96d56Sopenharmony_ci        "bsr %1, %0\n\t"
1157db96d56Sopenharmony_ci#endif
1167db96d56Sopenharmony_ci        :"=r" (retval)
1177db96d56Sopenharmony_ci        :"r" (a)
1187db96d56Sopenharmony_ci        :"cc"
1197db96d56Sopenharmony_ci    );
1207db96d56Sopenharmony_ci
1217db96d56Sopenharmony_ci    return (int)retval;
1227db96d56Sopenharmony_ci}
1237db96d56Sopenharmony_ci
1247db96d56Sopenharmony_ci/*
1257db96d56Sopenharmony_ci * Bit scan forward. Assumptions: a != 0.
1267db96d56Sopenharmony_ci */
1277db96d56Sopenharmony_cistatic inline int
1287db96d56Sopenharmony_cimpd_bsf(mpd_size_t a)
1297db96d56Sopenharmony_ci{
1307db96d56Sopenharmony_ci    mpd_size_t retval;
1317db96d56Sopenharmony_ci
1327db96d56Sopenharmony_ci    __asm__ (
1337db96d56Sopenharmony_ci#ifdef CONFIG_64
1347db96d56Sopenharmony_ci        "bsfq %1, %0\n\t"
1357db96d56Sopenharmony_ci#else
1367db96d56Sopenharmony_ci        "bsf %1, %0\n\t"
1377db96d56Sopenharmony_ci#endif
1387db96d56Sopenharmony_ci        :"=r" (retval)
1397db96d56Sopenharmony_ci        :"r" (a)
1407db96d56Sopenharmony_ci        :"cc"
1417db96d56Sopenharmony_ci    );
1427db96d56Sopenharmony_ci
1437db96d56Sopenharmony_ci    return (int)retval;
1447db96d56Sopenharmony_ci}
1457db96d56Sopenharmony_ci/* END ASM */
1467db96d56Sopenharmony_ci
1477db96d56Sopenharmony_ci#elif defined(MASM)
1487db96d56Sopenharmony_ci#include <intrin.h>
1497db96d56Sopenharmony_ci/*
1507db96d56Sopenharmony_ci * Bit scan reverse. Assumptions: a != 0.
1517db96d56Sopenharmony_ci */
1527db96d56Sopenharmony_cistatic inline int __cdecl
1537db96d56Sopenharmony_cimpd_bsr(mpd_size_t a)
1547db96d56Sopenharmony_ci{
1557db96d56Sopenharmony_ci    unsigned long retval;
1567db96d56Sopenharmony_ci
1577db96d56Sopenharmony_ci#ifdef CONFIG_64
1587db96d56Sopenharmony_ci    _BitScanReverse64(&retval, a);
1597db96d56Sopenharmony_ci#else
1607db96d56Sopenharmony_ci    _BitScanReverse(&retval, a);
1617db96d56Sopenharmony_ci#endif
1627db96d56Sopenharmony_ci
1637db96d56Sopenharmony_ci    return (int)retval;
1647db96d56Sopenharmony_ci}
1657db96d56Sopenharmony_ci
1667db96d56Sopenharmony_ci/*
1677db96d56Sopenharmony_ci * Bit scan forward. Assumptions: a != 0.
1687db96d56Sopenharmony_ci */
1697db96d56Sopenharmony_cistatic inline int __cdecl
1707db96d56Sopenharmony_cimpd_bsf(mpd_size_t a)
1717db96d56Sopenharmony_ci{
1727db96d56Sopenharmony_ci    unsigned long retval;
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci#ifdef CONFIG_64
1757db96d56Sopenharmony_ci    _BitScanForward64(&retval, a);
1767db96d56Sopenharmony_ci#else
1777db96d56Sopenharmony_ci    _BitScanForward(&retval, a);
1787db96d56Sopenharmony_ci#endif
1797db96d56Sopenharmony_ci
1807db96d56Sopenharmony_ci    return (int)retval;
1817db96d56Sopenharmony_ci}
1827db96d56Sopenharmony_ci/* END MASM (_MSC_VER) */
1837db96d56Sopenharmony_ci#else
1847db96d56Sopenharmony_ci  #error "missing preprocessor definitions"
1857db96d56Sopenharmony_ci#endif /* BSR/BSF */
1867db96d56Sopenharmony_ci
1877db96d56Sopenharmony_ci
1887db96d56Sopenharmony_ci#endif /* LIBMPDEC_BITS_H_ */
189