Skip to content

Commit 057151c

Browse files
hoshinolinamarcan
authored andcommitted
math: Add expf() implementation from musl
Signed-off-by: Asahi Lina <[email protected]>
1 parent 87fa247 commit 057151c

8 files changed

Lines changed: 470 additions & 7 deletions

File tree

Makefile

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,16 @@ CLANG_FORMAT := clang-format
3333
EXTRA_CFLAGS ?= -Wstack-usage=1024
3434
endif
3535

36-
CFLAGS := -O2 -Wall -g -Wundef -Werror=strict-prototypes -fno-common -fno-PIE \
36+
BASE_CFLAGS := -O2 -Wall -g -Wundef -Werror=strict-prototypes -fno-common -fno-PIE \
3737
-Werror=implicit-function-declaration -Werror=implicit-int \
3838
-Wsign-compare -Wunused-parameter -Wno-multichar \
3939
-ffreestanding -fpic -ffunction-sections -fdata-sections \
4040
-nostdinc -isystem $(shell $(CC) -print-file-name=include) -isystem sysinc \
41-
-fno-stack-protector -mgeneral-regs-only -mstrict-align -march=armv8.2-a \
41+
-fno-stack-protector -mstrict-align -march=armv8.2-a \
4242
$(EXTRA_CFLAGS)
4343

44+
CFLAGS := $(BASE_CFLAGS) -mgeneral-regs-only
45+
4446
CFG :=
4547
ifeq ($(RELEASE),1)
4648
CFG += RELEASE
@@ -127,7 +129,13 @@ OBJECTS := \
127129
wdt.o \
128130
$(MINILZLIB_OBJECTS) $(TINF_OBJECTS) $(DLMALLOC_OBJECTS) $(LIBFDT_OBJECTS) $(RUST_LIBS)
129131

132+
FP_OBJECTS := \
133+
math/expf.o \
134+
math/exp2f_data.o \
135+
130136
BUILD_OBJS := $(patsubst %,build/%,$(OBJECTS))
137+
BUILD_FP_OBJS := $(patsubst %,build/%,$(FP_OBJECTS))
138+
BUILD_ALL_OBJS := $(BUILD_OBJS) $(BUILD_FP_OBJS)
131139
NAME := m1n1
132140
TARGET := m1n1.macho
133141
TARGET_RAW := m1n1.bin
@@ -139,7 +147,7 @@ all: update_tag update_cfg build/$(TARGET) build/$(TARGET_RAW)
139147
clean:
140148
rm -rf build/*
141149
format:
142-
$(CLANG_FORMAT) -i src/*.c src/*.h sysinc/*.h
150+
$(CLANG_FORMAT) -i src/*.c src/math/*.c src/*.h src/math/*.h sysinc/*.h
143151
format-check:
144152
$(CLANG_FORMAT) --dry-run --Werror src/*.c src/*.h sysinc/*.h
145153
rustfmt:
@@ -160,6 +168,12 @@ build/%.o: src/%.S
160168
@mkdir -p "$(dir $@)"
161169
@$(AS) -c $(CFLAGS) -MMD -MF $(DEPDIR)/$(*F).d -MQ "$@" -MP -o $@ $<
162170

171+
$(BUILD_FP_OBJS): build/%.o: src/%.c
172+
@echo " CC[FP] $@"
173+
@mkdir -p $(DEPDIR)
174+
@mkdir -p "$(dir $@)"
175+
@$(CC) -c $(BASE_CFLAGS) -MMD -MF $(DEPDIR)/$(*F).d -MQ "$@" -MP -o $@ $<
176+
163177
build/%.o: src/%.c
164178
@echo " CC $@"
165179
@mkdir -p $(DEPDIR)
@@ -170,13 +184,13 @@ build/%.o: src/%.c
170184
invoke_cc:
171185
@$(CC) -c $(CFLAGS) -Isrc -o $(OBJFILE) $(CFILE)
172186

173-
build/$(NAME).elf: $(BUILD_OBJS) m1n1.ld
187+
build/$(NAME).elf: $(BUILD_ALL_OBJS) m1n1.ld
174188
@echo " LD $@"
175-
@$(LD) -T m1n1.ld $(LDFLAGS) -o $@ $(BUILD_OBJS)
189+
@$(LD) -T m1n1.ld $(LDFLAGS) -o $@ $(BUILD_ALL_OBJS)
176190

177-
build/$(NAME)-raw.elf: $(BUILD_OBJS) m1n1-raw.ld
191+
build/$(NAME)-raw.elf: $(BUILD_ALL_OBJS) m1n1-raw.ld
178192
@echo " LDRAW $@"
179-
@$(LD) -T m1n1-raw.ld $(LDFLAGS) -o $@ $(BUILD_OBJS)
193+
@$(LD) -T m1n1-raw.ld $(LDFLAGS) -o $@ $(BUILD_ALL_OBJS)
180194

181195
build/$(NAME).macho: build/$(NAME).elf
182196
@echo " MACHO $@"

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,7 @@ licensed under the [OFL-1.1](3rdparty_licenses/LICENSE.OFL-1.1) license and copy
132132
m1n1 embeds portions of the [dwc3 usb linux driver](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/dwc3/core.h?id=7bc5a6ba369217e0137833f5955cf0b0f08b0712), which was [BSD-or-GPLv2 dual-licensed](3rdparty_licenses/LICENSE.BSD-3.dwc3) and copyright
133133
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
134134

135+
m1n1 embeds portions of [musl-libc](https://musl.libc.org/)'s floating point library, which are MIT licensed and copyright
136+
* Copyright (c) 2017-2018, Arm Limited.
137+
135138
m1n1 embeds some rust crates. Licenses can be found in the vendor directory for every crate.

src/math/exp2f_data.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Shared data between expf, exp2f and powf.
3+
*
4+
* Copyright (c) 2017-2018, Arm Limited.
5+
* SPDX-License-Identifier: MIT
6+
*/
7+
8+
#include "exp2f_data.h"
9+
10+
#define N (1 << EXP2F_TABLE_BITS)
11+
12+
const struct exp2f_data __exp2f_data = {
13+
/* tab[i] = uint(2^(i/N)) - (i << 52-BITS)
14+
used for computing 2^(k/N) for an int |k| < 150 N as
15+
double(tab[k%N] + (k << 52-BITS)) */
16+
.tab =
17+
{
18+
0x3ff0000000000000, 0x3fefd9b0d3158574, 0x3fefb5586cf9890f, 0x3fef9301d0125b51,
19+
0x3fef72b83c7d517b, 0x3fef54873168b9aa, 0x3fef387a6e756238, 0x3fef1e9df51fdee1,
20+
0x3fef06fe0a31b715, 0x3feef1a7373aa9cb, 0x3feedea64c123422, 0x3feece086061892d,
21+
0x3feebfdad5362a27, 0x3feeb42b569d4f82, 0x3feeab07dd485429, 0x3feea47eb03a5585,
22+
0x3feea09e667f3bcd, 0x3fee9f75e8ec5f74, 0x3feea11473eb0187, 0x3feea589994cce13,
23+
0x3feeace5422aa0db, 0x3feeb737b0cdc5e5, 0x3feec49182a3f090, 0x3feed503b23e255d,
24+
0x3feee89f995ad3ad, 0x3feeff76f2fb5e47, 0x3fef199bdd85529c, 0x3fef3720dcef9069,
25+
0x3fef5818dcfba487, 0x3fef7c97337b9b5f, 0x3fefa4afa2a490da, 0x3fefd0765b6e4540,
26+
},
27+
.shift_scaled = 0x1.8p+52 / N,
28+
.poly =
29+
{
30+
0x1.c6af84b912394p-5,
31+
0x1.ebfce50fac4f3p-3,
32+
0x1.62e42ff0c52d6p-1,
33+
},
34+
.shift = 0x1.8p+52,
35+
.invln2_scaled = 0x1.71547652b82fep+0 * N,
36+
.poly_scaled =
37+
{
38+
0x1.c6af84b912394p-5 / N / N / N,
39+
0x1.ebfce50fac4f3p-3 / N / N,
40+
0x1.62e42ff0c52d6p-1 / N,
41+
},
42+
};

src/math/exp2f_data.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (c) 2017-2018, Arm Limited.
3+
* SPDX-License-Identifier: MIT
4+
*/
5+
#ifndef _EXP2F_DATA_H
6+
#define _EXP2F_DATA_H
7+
8+
#include <stdint.h>
9+
10+
/* Shared between expf, exp2f and powf. */
11+
#define EXP2F_TABLE_BITS 5
12+
#define EXP2F_POLY_ORDER 3
13+
extern const struct exp2f_data {
14+
uint64_t tab[1 << EXP2F_TABLE_BITS];
15+
double shift_scaled;
16+
double poly[EXP2F_POLY_ORDER];
17+
double shift;
18+
double invln2_scaled;
19+
double poly_scaled[EXP2F_POLY_ORDER];
20+
} __exp2f_data;
21+
22+
#endif

src/math/expf.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Single-precision e^x function.
3+
*
4+
* Copyright (c) 2017-2018, Arm Limited.
5+
* SPDX-License-Identifier: MIT
6+
*/
7+
8+
#include <math.h>
9+
#include <stdint.h>
10+
11+
#include "exp2f_data.h"
12+
#include "libm.h"
13+
14+
#define double_t double
15+
16+
/*
17+
EXP2F_TABLE_BITS = 5
18+
EXP2F_POLY_ORDER = 3
19+
20+
ULP error: 0.502 (nearest rounding.)
21+
Relative error: 1.69 * 2^-34 in [-ln2/64, ln2/64] (before rounding.)
22+
Wrong count: 170635 (all nearest rounding wrong results with fma.)
23+
Non-nearest ULP error: 1 (rounded ULP error)
24+
*/
25+
26+
#define N (1 << EXP2F_TABLE_BITS)
27+
#define InvLn2N __exp2f_data.invln2_scaled
28+
#define T __exp2f_data.tab
29+
#define C __exp2f_data.poly_scaled
30+
31+
static inline uint32_t top12(float x)
32+
{
33+
return asuint(x) >> 20;
34+
}
35+
36+
float expf(float x)
37+
{
38+
uint32_t abstop;
39+
uint64_t ki, t;
40+
double_t kd, xd, z, r, r2, y, s;
41+
42+
xd = (double_t)x;
43+
abstop = top12(x) & 0x7ff;
44+
if (predict_false(abstop >= top12(88.0f))) {
45+
/* |x| >= 88 or x is nan. */
46+
if (asuint(x) == asuint(-INFINITY))
47+
return 0.0f;
48+
if (abstop >= top12(INFINITY))
49+
return x + x;
50+
if (x > 0x1.62e42ep6f) /* x > log(0x1p128) ~= 88.72 */
51+
return __math_oflowf(0);
52+
if (x < -0x1.9fe368p6f) /* x < log(0x1p-150) ~= -103.97 */
53+
return __math_uflowf(0);
54+
}
55+
56+
/* x*N/Ln2 = k + r with r in [-1/2, 1/2] and int k. */
57+
z = InvLn2N * xd;
58+
59+
/* Round and convert z to int, the result is in [-150*N, 128*N] and
60+
ideally ties-to-even rule is used, otherwise the magnitude of r
61+
can be bigger which gives larger approximation error. */
62+
#if TOINT_INTRINSICS
63+
kd = roundtoint(z);
64+
ki = converttoint(z);
65+
#else
66+
#define SHIFT __exp2f_data.shift
67+
kd = eval_as_double(z + SHIFT);
68+
ki = asuint64(kd);
69+
kd -= SHIFT;
70+
#endif
71+
r = z - kd;
72+
73+
/* exp(x) = 2^(k/N) * 2^(r/N) ~= s * (C0*r^3 + C1*r^2 + C2*r + 1) */
74+
t = T[ki % N];
75+
t += ki << (52 - EXP2F_TABLE_BITS);
76+
s = asdouble(t);
77+
z = C[0] * r + C[1];
78+
r2 = r * r;
79+
y = C[2] * r + 1;
80+
y = z * r2 + y;
81+
y = y * s;
82+
return eval_as_float(y);
83+
}

0 commit comments

Comments
 (0)