TFG-benchmarks/zfa_micro/zfa.c
2026-06-12 09:00:52 +02:00

309 lines
6.7 KiB
C

#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#define N 10
#define ZFA
int32_t emulate_fcvtmod_w_d(double a) {
// 1. Trap NaNs and Infinities (Spec says they must return 0)
if (!isfinite(a)) {
return 0;
}
// 2. Bring the double into a range that fits in a 64-bit int.
// We use fmod to strip away everything above 2^32.
// (2^32 is exactly 4294967296.0)
double truncated_range = fmod(a, 4294967296.0);
// 3. Convert to 64-bit integer with truncation (RTZ)
int64_t standard_int = (int64_t)truncated_range;
// 4. Cast to 32-bit signed integer (effectively your SLLI/SRAI)
return (int32_t)standard_int;
}
static int baremetal_errno = 0;
int *__errno(void) {
return &baremetal_errno;
}
static inline uint64_t read_cycles() {
uint64_t start;
asm volatile ("rdcycle %0" : "=r"(start));
return start;
}
int main() {
// -- fround.s --
{
volatile float a, b;
read_cycles();
for (int i = 0; i < N; i++) {
a = 3.25f;
b = round(a);
}
read_cycles();
}
// -- fround.d --
{
volatile double a, b;
read_cycles();
for (int i = 0; i < N; i++) {
a = 3.25;
b = round(a);
}
read_cycles();
}
// -- fleq.s --
{
volatile float a = 3.25f, b = 3.0f;
int res;
read_cycles();
for (int i = 0; i < N; i++) {
#ifndef ZFA
asm volatile (
"fclass.s t0, %1\n\t"
"fclass.s t1, %2\n\t"
"or t0, t0, t1\n\t"
"andi t2, t0, 0x200\n\t"
"bnez t2, 1f\n\t"
"fle.s %0, %1, %2\n\t"
"j 2f\n\t"
"1:\n\t"
"li %0, 0\n\t"
"2:\n\t"
: "=r" (res)
: "f" (a), "f" (b)
: "t0", "t1", "t2"
);
#else
asm volatile ("fleq.s %0, %1, %2" : "=r" (res) : "f" (a), "f" (b));
#endif
}
read_cycles();
}
// -- fleq.d --
{
volatile double a = 3.25, b = 3.0;
int res;
read_cycles();
for (int i = 0; i < N; i++) {
#ifndef ZFA
asm volatile (
"fclass.d t0, %1\n\t"
"fclass.d t1, %2\n\t"
"or t0, t0, t1\n\t"
"andi t2, t0, 0x200\n\t"
"bnez t2, 1f\n\t"
"fle.d %0, %1, %2\n\t"
"j 2f\n\t"
"1:\n\t"
"li %0, 0\n\t"
"2:\n\t"
: "=r" (res)
: "f" (a), "f" (b)
: "t0", "t1", "t2"
);
#else
asm volatile ("fleq.d %0, %1, %2" : "=r" (res) : "f" (a), "f" (b));
#endif
}
read_cycles();
}
// -- fminm.s --
{
volatile float a = 0.0f, b = -0.0f, res;
read_cycles();
for (int i = 0; i < N; i++) {
#ifndef ZFA
asm volatile (
"fclass.s t0, %1\n\t"
"fclass.s t1, %2\n\t"
"li t2, 0x300\n\t"
"and t3, t0, t2\n\t"
"and t4, t1, t2\n\t"
"bnez t3, 1f\n\t"
"bnez t4, 2f\n\t"
"fmin.s %0, %1, %2\n\t"
"j 3f\n\t"
"1:\n\t"
"bnez t4, 4f\n\t"
"fmv.s %0, %2\n\t"
"j 3f\n\t"
"2:\n\t"
"fmv.s %0, %1\n\t"
"j 3f\n\t"
"4:\n\t"
"fmin.s %0, %1, %2\n\t"
"3:\n\t"
: "=f" (res)
: "f" (a), "f" (b)
: "t0", "t1", "t2", "t3", "t4"
);
#else
asm volatile ("fminm.s %0, %1, %2" : "=f" (res) : "f" (a), "f" (b));
#endif
}
read_cycles();
}
// -- fminm.d --
{
volatile double a = 0.0, b = -0.0, res;
read_cycles();
for (int i = 0; i < N; i++) {
#ifndef ZFA
asm volatile (
"fclass.d t0, %1\n\t"
"fclass.d t1, %2\n\t"
"li t2, 0x300\n\t"
"and t3, t0, t2\n\t"
"and t4, t1, t2\n\t"
"bnez t3, 1f\n\t"
"bnez t4, 2f\n\t"
"fmin.d %0, %1, %2\n\t"
"j 3f\n\t"
"1:\n\t"
"bnez t4, 4f\n\t"
"fmv.d %0, %2\n\t"
"j 3f\n\t"
"2:\n\t"
"fmv.d %0, %1\n\t"
"j 3f\n\t"
"4:\n\t"
"fmin.d %0, %1, %2\n\t"
"3:\n\t"
: "=f" (res)
: "f" (a), "f" (b)
: "t0", "t1", "t2", "t3", "t4"
);
#else
asm volatile ("fminm.d %0, %1, %2" : "=f" (res) : "f" (a), "f" (b));
#endif
}
read_cycles();
}
// -- fli.s --
{
volatile float res[32];
read_cycles();
for (int i = 0; i < N; i++) {
res[0] = -1.0f;
res[1] = -1.0f;
res[2] = 0x1p-16f;
res[3] = 0x1p-15f;
res[4] = 0x1p-14f;
res[5] = 0x1p-13f;
res[6] = 0x1p-12f;
res[7] = 0x1p-11f;
res[8] = 0x1p-10f;
res[9] = 0x1p-9f;
res[10] = 0x1p-8f;
res[11] = 0x1p-7f;
res[12] = 0x1p-6f;
res[13] = 0x1p-5f;
res[14] = 0x1p-4f;
res[15] = 0x1p-3f;
res[16] = 0.25f;
res[17] = 0.5f;
res[18] = 0.75f;
res[19] = 1.0f;
res[20] = 1.25f;
res[21] = 1.5f;
res[22] = 1.75f;
res[23] = 2.0f;
res[24] = 2.5f;
res[25] = 3.0f;
res[26] = 4.0f;
res[27] = 8.0f;
res[28] = 16.0f;
res[29] = 32.0f;
res[30] = INFINITY;
res[31] = NAN;
}
read_cycles();
}
// -- fli.d --
{
volatile double res[32];
read_cycles();
for (int i = 0; i < N; i++) {
res[0] = -1.0;
res[1] = -1.0;
res[2] = 0x1p-16;
res[3] = 0x1p-15;
res[4] = 0x1p-14;
res[5] = 0x1p-13;
res[6] = 0x1p-12;
res[7] = 0x1p-11;
res[8] = 0x1p-10;
res[9] = 0x1p-9;
res[10] = 0x1p-8;
res[11] = 0x1p-7;
res[12] = 0x1p-6;
res[13] = 0x1p-5;
res[14] = 0x1p-4;
res[15] = 0x1p-3;
res[16] = 0.25;
res[17] = 0.5;
res[18] = 0.75;
res[19] = 1.0;
res[20] = 1.25;
res[21] = 1.5;
res[22] = 1.75;
res[23] = 2.0;
res[24] = 2.5;
res[25] = 3.0;
res[26] = 4.0;
res[27] = 8.0;
res[28] = 16.0;
res[29] = 32.0;
res[30] = INFINITY;
res[31] = NAN;
}
read_cycles();
}
// -- fcvtmod.w.d --
{
static const double inputs[N] = {
2147483649.0, // 2^31 + 1 -> -2147483647 (mod 2^32)
-2147483649.0, // -2^31 - 1 -> 2147483647 (mod 2^32)
4294967297.0, // 2^32 + 1 -> 1 (mod 2^32)
-4294967297.0, // -2^32 - 1 -> -1 (mod 2^32)
3.25, // in-range
0.0, // exact zero
-0.0, // negative zero
INFINITY,
-INFINITY,
NAN
};
volatile double a;
int32_t res;
read_cycles();
for (int i = 0; i < N; i++) {
a = inputs[i];
asm volatile("" : "+f"(a));
#ifndef ZFA
res = emulate_fcvtmod_w_d(a);
#else
asm volatile ("fcvtmod.w.d %0, %1, rtz" : "=r" (res) : "f" (a));
#endif
asm volatile("" : : "r"(res));
}
read_cycles();
}
return 0;
}