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 */
41typedef 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
52int64_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
79int64_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
107int64_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
142OT_ALIAS("_ot_builtin_lshift_i64")
143int64_t __ashldi3(int64_t val, int32_t shift);
145OT_ALIAS("_ot_builtin_rshift_i64")
146int64_t __lshrdi3(int64_t val, int32_t shift);
148OT_ALIAS("_ot_builtin_ashift_i64")
149int64_t __ashrdi3(int64_t val, int32_t shift);
150
151extern 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.
160OT_WEAK int64_t __divdi3(int64_t a, int64_t b) {
161 _ot_builtin_div64_intentionally_not_implemented_see_pull_11451();
162}
163OT_WEAK uint64_t __udivdi3(uint64_t a, uint64_t b) {
164 _ot_builtin_div64_intentionally_not_implemented_see_pull_11451();
165}
166OT_WEAK int64_t __moddi3(int64_t a, int64_t b) {
167 _ot_builtin_div64_intentionally_not_implemented_see_pull_11451();
168}
169OT_WEAK uint64_t __umoddi3(uint64_t a, uint64_t b) {
170 _ot_builtin_div64_intentionally_not_implemented_see_pull_11451();
171}
172OT_WEAK int64_t __divmoddi4(int64_t a, int64_t b, int64_t *rem) {
173 _ot_builtin_div64_intentionally_not_implemented_see_pull_11451();
174}
175OT_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