Software APIs
math_builtins.c
Go to the documentation of this file.
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 /**
6  * @file
7  * @brief Implementations of libgcc-style polyfills for arithmetic.
8  *
9  * This file has no header, since its functions should not be called directly;
10  * the compiler will generate calls into them as needed.
11  *
12  * The functions have names like `_ot_builtin_*`, rather than their libgcc
13  * names, so that they can coexist with libgcc/libcompiler-rt on the host-side
14  * for the purpose of unit tests. The linker aliases for the libgcc names only
15  * exist on the device-side.
16  *
17  * See https://github.com/llvm/llvm-project/tree/main/compiler-rt/lib/builtins
18  * for a detailed specification of the ABI we implement in this file.
19  *
20  * The provided functions here are:
21  * - 64-bit shifts.
22  * - 32-bit popcount, parity, bswap, clz, ctz, and find first.
23  *
24  * Although the RISC-V B extension provides instructions for some ofthese, we
25  * currently do not require using a Clang that is aware of how to codegen them,
26  * so LLVM may choose to emit libgcc polyfill symbols (like the following)
27  * instead. Once we mandate such a Clang, they should be removed.
28  */
29 
30 #include <stdint.h>
31 #include <stdnoreturn.h>
32 
34 
35 /**
36  * Helper type for fussing with the upper and lower halves of an i64.
37  *
38  * This is necessary to avoid accidentally calling into the shift polyfills
39  * inside of their implementations.
40  */
41 typedef union u32x2 {
42  struct {
43  uint32_t lo;
44  union {
45  uint32_t hi;
46  int32_t hi_signed;
47  };
48  };
49  int64_t full;
51 
52 int64_t _ot_builtin_lshift_i64(int64_t val, int32_t shift) {
53  if (shift == 0) {
54  return val;
55  }
56 
57  u32x2_t word = {.full = val};
58 
59  // When doing a big shift, we have
60  //
61  // aaaa'aaaa'bbbb'bbbb
62  // bbbb'bb00'0000'0000
63  if (shift >= 32) {
64  word.hi = word.lo << (shift - 32);
65  word.lo = 0;
66  return word.full;
67  }
68 
69  // When doing a small shift, we have
70  //
71  // aaaa'aaaa'bbbb'bbbb
72  // aaaa'aabb'bbbb'bb00
73  word.hi <<= shift;
74  word.hi |= word.lo >> (32 - shift);
75  word.lo <<= shift;
76  return word.full;
77 }
78 
79 int64_t _ot_builtin_rshift_i64(int64_t val, int32_t shift) {
80  if (shift == 0) {
81  return val;
82  }
83 
84  u32x2_t word = {.full = val};
85 
86  // When doing a big shift, we have
87  //
88  // aaaa'aaaa'bbbb'bbbb
89  // 0000'0000'00aa'aaaa
90  if (shift >= 32) {
91  word.lo = word.hi >> (shift - 32);
92  word.hi = 0;
93  return word.full;
94  }
95 
96  // When doing a small shift, we have
97  //
98  // aaaa'aaaa'bbbb'bbbb
99  // 00aa'aaaa'aabb'bbbb
100  word.lo >>= shift;
101  word.lo |= word.hi << (32 - shift);
102  word.hi >>= shift;
103 
104  return word.full;
105 }
106 
107 int64_t _ot_builtin_ashift_i64(int64_t val, int32_t shift) {
108  if (shift == 0) {
109  return val;
110  }
111 
112  u32x2_t word = {.full = val};
113 
114  // When doing a big shift, we have
115  //
116  // aaaa'aaaa'bbbb'bbbb
117  // ssss'ssss'ssaa'aaaa
118  //
119  // where s is sign bits.
120  if (shift >= 32) {
121  word.lo = (uint32_t)(word.hi_signed >> (shift - 32));
122  word.hi_signed >>= 31;
123  return word.full;
124  }
125 
126  // When doing a small shift, we have
127  //
128  // aaaa'aaaa'bbbb'bbbb
129  // ssaa'aaaa'aabb'bbbb
130  //
131  // where s is sign bits.
132  word.lo >>= shift;
133  word.lo |= word.hi << (32 - shift);
134  word.hi_signed >>= shift;
135 
136  return word.full;
137 }
138 
139 // Linker aliases for libgcc symbols.
140 #ifdef OT_PLATFORM_RV32
141 OT_WEAK
142 OT_ALIAS("_ot_builtin_lshift_i64")
143 int64_t __ashldi3(int64_t val, int32_t shift);
144 OT_WEAK
145 OT_ALIAS("_ot_builtin_rshift_i64")
146 int64_t __lshrdi3(int64_t val, int32_t shift);
147 OT_WEAK
148 OT_ALIAS("_ot_builtin_ashift_i64")
149 int64_t __ashrdi3(int64_t val, int32_t shift);
150 
151 extern noreturn void
152 _ot_builtin_div64_intentionally_not_implemented_see_pull_11451(void);
153 
154 // "Trap" polyfills to catch uses of u64 divsion and display an "error" via
155 // the name of an undefined symbol.
156 //
157 // Of course, this depends on people linking this file in... but hopefully it
158 // is sufficiently pervasive that won't be an issue; at any rate, it means
159 // people will land somewhere when they grep for __udivdi3 and friends.
160 OT_WEAK int64_t __divdi3(int64_t a, int64_t b) {
161  _ot_builtin_div64_intentionally_not_implemented_see_pull_11451();
162 }
163 OT_WEAK uint64_t __udivdi3(uint64_t a, uint64_t b) {
164  _ot_builtin_div64_intentionally_not_implemented_see_pull_11451();
165 }
166 OT_WEAK int64_t __moddi3(int64_t a, int64_t b) {
167  _ot_builtin_div64_intentionally_not_implemented_see_pull_11451();
168 }
169 OT_WEAK uint64_t __umoddi3(uint64_t a, uint64_t b) {
170  _ot_builtin_div64_intentionally_not_implemented_see_pull_11451();
171 }
172 OT_WEAK int64_t __divmoddi4(int64_t a, int64_t b, int64_t *rem) {
173  _ot_builtin_div64_intentionally_not_implemented_see_pull_11451();
174 }
175 OT_WEAK uint64_t __udivmoddi4(uint64_t a, uint64_t b, uint64_t *rem) {
176  _ot_builtin_div64_intentionally_not_implemented_see_pull_11451();
177 }
178 #endif // OT_PLATFORM_RV32