blob: 554a7a2b7c6a7cc15d2eedf8e9fe02b493ec1f19 [file] [log] [blame]
Eric Kunzee5e26762020-10-13 16:11:07 -07001
2// Copyright (c) 2020, ARM Limited.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16/*
17 * Filename: src/arith_util.h
18 * Description:
19 * arithmetic utility macro, include:
20 * fp16 (float16_t ) type alias
21 * bitwise operation
22 * fix point arithmetic
23 * fp16 type conversion(in binary translation)
24 * fp16 arithmetic (disguised with fp32 now)
25 */
26
27#ifndef ARITH_UTIL_H
28#define ARITH_UTIL_H
29
30#include <fenv.h>
31#include <math.h>
32#define __STDC_LIMIT_MACROS //enable min/max of plain data type
33#include "func_debug.h"
34#include "inttypes.h"
35#include <cassert>
36#include <iostream>
37#include <limits>
38#include <stdint.h>
39#include <typeinfo>
40
41using namespace std;
42
43inline size_t _count_one(uint64_t val)
44{
45 size_t count = 0;
46 for (; val; count++)
47 {
48 val &= val - 1;
49 }
50 return count;
51}
52
53template <typename T>
54inline size_t _integer_log2(T val)
55{
56 size_t result = 0;
57 while (val >>= 1)
58 {
59 ++result;
60 }
61 return result;
62}
63
64template <typename T>
65inline size_t _count_leading_zeros(T val)
66{
67 size_t size = sizeof(T) * 8;
68 size_t count = 0;
69 T msb = static_cast<T>(1) << (size - 1);
70 for (size_t i = 0; i < size; i++)
71 {
72 if (!((val << i) & msb))
73 count++;
74 else
75 break;
76 }
77 return count;
78}
79
80template <typename T>
81inline size_t _count_leading_ones(T val)
82{
83 size_t size = sizeof(T) * 8;
84 size_t count = 0;
85 T msb = static_cast<T>(1) << (size - 1);
86 for (size_t i = 0; i < size; i++)
87 {
88 if ((val << i) & msb)
89 count++;
90 else
91 break;
92 }
93 return count;
94}
95
96#define MAX(a, b) ((a) > (b) ? (a) : (b))
97#define MIN(a, b) ((a) < (b) ? (a) : (b))
98// Compute ceiling of (a/b)
99#define DIV_CEIL(a, b) ((a) % (b) ? ((a) / (b) + 1) : ((a) / (b)))
100
101// Returns a mask of 1's of this size
102#define ONES_MASK(SIZE) ((uint64_t)((SIZE) >= 64 ? 0xffffffffffffffffULL : ((uint64_t)(1) << (SIZE)) - 1))
103
104// Returns a field of bits from HIGH_BIT to LOW_BIT, right-shifted
105// include both side, equivalent VAL[LOW_BIT:HIGH_BIT] in verilog
106
107#define BIT_FIELD(HIGH_BIT, LOW_BIT, VAL) (((uint64_t)(VAL) >> (LOW_BIT)) & ONES_MASK((HIGH_BIT) + 1 - (LOW_BIT)))
108
109// Returns a bit at a particular position
110#define BIT_EXTRACT(POS, VAL) (((uint64_t)(VAL) >> (POS)) & (1))
111
112// Use Brian Kernigahan's way: https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
113// Does this need to support floating point type?
114// Not sure if static_cast is the right thing to do, try to be type safe first
115#define ONES_COUNT(VAL) (_count_one((uint64_t)(VAL)))
116
117#define SHIFT(SHF, VAL) (((SHF) > 0) ? ((VAL) << (SHF)) : ((SHF < 0) ? ((VAL) >> (-(SHF))) : (VAL)))
118#define ROUNDTO(A, B) ((A) % (B) == 0 ? (A) : ((A) / (B) + 1) * (B))
119#define ROUNDTOLOWER(A, B) (((A) / (B)) * (B))
120#define BIDIRECTIONAL_SHIFT(VAL, SHIFT) (((SHIFT) >= 0) ? ((VAL) << (SHIFT)) : ((VAL) >> (-(SHIFT))))
121#define ILOG2(VAL) (_integer_log2(VAL))
122
123// Get negative value (2's complement)
124#define NEGATIVE_8(VAL) ((uint8_t)(~(VAL) + 1))
125#define NEGATIVE_16(VAL) ((uint16_t)(~(VAL) + 1))
126#define NEGATIVE_32(VAL) ((uint32_t)(~(VAL) + 1))
127#define NEGATIVE_64(VAL) ((uint64_t)(~(VAL) + 1))
128// Convert a bit quanity to the minimum bytes required to hold those bits
129#define BITS_TO_BYTES(BITS) (ROUNDTO((BITS), 8) / 8)
130
131// Count leading zeros/ones for 8/16/32/64-bit operands
132// (I don't see an obvious way to collapse this into a size-independent set)
133// treated as unsigned
134#define LEADING_ZEROS_64(VAL) (_count_leading_zeros((uint64_t)(VAL)))
135#define LEADING_ZEROS_32(VAL) (_count_leading_zeros((uint32_t)(VAL)))
136#define LEADING_ZEROS_16(VAL) (_count_leading_zeros((uint16_t)(VAL)))
137#define LEADING_ZEROS_8(VAL) (_count_leading_zeros((uint8_t)(VAL)))
138#define LEADING_ZEROS(VAL) (_count_leading_zeros(VAL))
139
140#define LEADING_ONES_64(VAL) _count_leading_ones((uint64_t)(VAL))
141#define LEADING_ONES_32(VAL) _count_leading_ones((uint32_t)(VAL))
142#define LEADING_ONES_16(VAL) _count_leading_ones((uint16_t)(VAL))
143#define LEADING_ONES_8(VAL) _count_leading_ones((uint8_t)(VAL))
144#define LEADING_ONES(VAL) _count_leading_ones(VAL)
145// math operation
146// sign-extended for signed version
147// extend different return type (8, 16, 32) + (S, U)
148// Saturate a value at a certain bitwidth, signed and unsigned versions
149// Format is as followed: SATURATE_VAL_{saturation_sign}_{return_type}
150// for example
151// SATURATE_VAL_U_8U(8,300) will return uint8_t with value of 255(0xff)
152// SATURATE_VAL_S_32S(5,-48) will return int32_t with value of -16(0x10)
153// note that negative value can cast to unsigned return type using native uint(int) cast
154// so SATURATE_VAL_S_8U(5,-40) will have value 0'b1110000 which is in turn 224 in uint8_t
155
156template <typename T>
157constexpr T bitmask(const uint32_t width)
158{
159 ASSERT(width <= sizeof(T) * 8);
160 return width == sizeof(T) * 8 ? static_cast<T>(std::numeric_limits<uintmax_t>::max())
161 : (static_cast<T>(1) << width) - 1;
162}
163
164template <typename T>
165constexpr T minval(const uint32_t width)
166{
167 ASSERT(width <= sizeof(T) * 8);
168 return std::is_signed<T>::value ? -(static_cast<T>(1) << (width - 1)) : 0;
169}
170
171template <typename T>
172constexpr T maxval(const uint32_t width)
173{
174 ASSERT(width <= sizeof(T) * 8);
175 return bitmask<T>(width - std::is_signed<T>::value);
176}
177
178template <typename T>
179constexpr T saturate(const uint32_t width, const intmax_t value)
180{
181 // clang-format off
182 return static_cast<T>(
183 std::min(
184 std::max(
185 value,
186 static_cast<intmax_t>(minval<T>(width))
187 ),
188 static_cast<intmax_t>(maxval<T>(width))
189 )
190 );
191 // clang-format on
192}
193
194#endif /* _ARITH_UTIL_H */