summaryrefslogtreecommitdiffstats
path: root/src/common/bit_util.h
blob: 6f7d5a94798f26077b6fd376e4f30b3eb6f89c1a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <climits>
#include <cstddef>

#ifdef _MSC_VER
#include <intrin.h>
#endif

#include "common/common_types.h"

namespace Common {

/// Gets the size of a specified type T in bits.
template <typename T>
constexpr std::size_t BitSize() {
    return sizeof(T) * CHAR_BIT;
}

#ifdef _MSC_VER
inline u32 CountLeadingZeroes32(u32 value) {
    unsigned long leading_zero = 0;

    if (_BitScanReverse(&leading_zero, value) != 0) {
        return 31 - leading_zero;
    }

    return 32;
}

inline u32 CountLeadingZeroes64(u64 value) {
    unsigned long leading_zero = 0;

    if (_BitScanReverse64(&leading_zero, value) != 0) {
        return 63 - leading_zero;
    }

    return 64;
}
#else
inline u32 CountLeadingZeroes32(u32 value) {
    if (value == 0) {
        return 32;
    }

    return static_cast<u32>(__builtin_clz(value));
}

inline u32 CountLeadingZeroes64(u64 value) {
    if (value == 0) {
        return 64;
    }

    return static_cast<u32>(__builtin_clzll(value));
}
#endif

#ifdef _MSC_VER
inline u32 CountTrailingZeroes32(u32 value) {
    unsigned long trailing_zero = 0;

    if (_BitScanForward(&trailing_zero, value) != 0) {
        return trailing_zero;
    }

    return 32;
}

inline u32 CountTrailingZeroes64(u64 value) {
    unsigned long trailing_zero = 0;

    if (_BitScanForward64(&trailing_zero, value) != 0) {
        return trailing_zero;
    }

    return 64;
}
#else
inline u32 CountTrailingZeroes32(u32 value) {
    if (value == 0) {
        return 32;
    }

    return static_cast<u32>(__builtin_ctz(value));
}

inline u32 CountTrailingZeroes64(u64 value) {
    if (value == 0) {
        return 64;
    }

    return static_cast<u32>(__builtin_ctzll(value));
}
#endif

#ifdef _MSC_VER

inline u32 MostSignificantBit32(const u32 value) {
    unsigned long result;
    _BitScanReverse(&result, value);
    return static_cast<u32>(result);
}

inline u32 MostSignificantBit64(const u64 value) {
    unsigned long result;
    _BitScanReverse64(&result, value);
    return static_cast<u32>(result);
}

#else

inline u32 MostSignificantBit32(const u32 value) {
    return 31U - static_cast<u32>(__builtin_clz(value));
}

inline u32 MostSignificantBit64(const u64 value) {
    return 63U - static_cast<u32>(__builtin_clzll(value));
}

#endif

inline u32 Log2Floor32(const u32 value) {
    return MostSignificantBit32(value);
}

inline u32 Log2Ceil32(const u32 value) {
    const u32 log2_f = Log2Floor32(value);
    return log2_f + ((value ^ (1U << log2_f)) != 0U);
}

inline u32 Log2Floor64(const u64 value) {
    return MostSignificantBit64(value);
}

inline u32 Log2Ceil64(const u64 value) {
    const u64 log2_f = static_cast<u64>(Log2Floor64(value));
    return static_cast<u32>(log2_f + ((value ^ (1ULL << log2_f)) != 0ULL));
}

} // namespace Common