Skip to content

Commit

Permalink
sw/math: Add safe FP <--> INT conversions
Browse files Browse the repository at this point in the history
  • Loading branch information
colluca committed Nov 8, 2023
1 parent 81fe099 commit c26197a
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
From eb96f4d7454a07498f571eb1ed18aa1db2413551 Mon Sep 17 00:00:00 2001
From: Luca Colagrande <[email protected]>
Date: Mon, 23 Oct 2023 16:45:17 +0200
Subject: [PATCH] `sw/math`: Add safe FP <--> INT conversions

---
src/internal/libm.h | 51 +++++++++++++++++++++++++++++++++++++++++----
1 file changed, 47 insertions(+), 4 deletions(-)

diff --git a/src/internal/libm.h b/src/internal/libm.h
index 72ad17d..60b9866 100644
--- a/src/internal/libm.h
+++ b/src/internal/libm.h
@@ -96,6 +96,47 @@ static int32_t converttoint(double_t);
#define predict_false(x) (x)
#endif

+/* FPU fence to synchronize the FPU and integer core in Snitch. */
+inline void snrt_fpu_fence() {
+ unsigned tmp;
+ __asm__ volatile(
+ "fmv.x.w %0, fa0\n"
+ "mv %0, %0\n"
+ : "+r"(tmp)::"memory");
+}
+
+/* Synch-secure double to uint64 conversion functions. */
+static inline uint64_t asuint64(double f) {
+ uint64_t result;
+ snrt_fpu_fence();
+ result = *(uint64_t *)&f;
+ return result;
+}
+
+/* Synch-secure float to uint conversion functions. */
+static inline uint64_t asuint(float f) {
+ uint32_t result;
+ snrt_fpu_fence();
+ result = *(uint32_t *)&f;
+ return result;
+}
+
+/* Synch-secure uint64 to double conversion functions. */
+static inline double asdouble(uint64_t i) {
+ double result;
+ snrt_fpu_fence();
+ result = *(double *)&i;
+ return result;
+}
+
+/* Synch-secure uint to float conversion functions. */
+static inline float asfloat(uint32_t i) {
+ float result;
+ snrt_fpu_fence();
+ result = *(float *)&i;
+ return result;
+}
+
/* Evaluate an expression as the specified type. With standard excess
precision handling a type cast or assignment is enough (with
-ffloat-store an assignment is required, in old compilers argument
@@ -187,10 +228,12 @@ static inline void fp_force_evall(long double x)
} \
} while(0)

-#define asuint(f) ((union{float _f; uint32_t _i;}){f})._i
-#define asfloat(i) ((union{uint32_t _i; float _f;}){i})._f
-#define asuint64(f) ((union{double _f; uint64_t _i;}){f})._i
-#define asdouble(i) ((union{uint64_t _i; double _f;}){i})._f
+// Unsafe in Snitch due to the decoupled FPU and integer
+// arithmetic units. Use at your own risk.
+#define asuint_unsafe(f) ((union{float _f; uint32_t _i;}){f})._i
+#define asfloat_unsafe(i) ((union{uint32_t _i; float _f;}){i})._f
+#define asuint64_unsafe(f) ((union{double _f; uint64_t _i;}){f})._i
+#define asdouble_unsafe(i) ((union{uint64_t _i; double _f;}){i})._f

#define EXTRACT_WORDS(hi,lo,d) \
do { \
--
2.28.0

51 changes: 47 additions & 4 deletions sw/math/src/internal/libm.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,47 @@ static int32_t converttoint(double_t);
#define predict_false(x) (x)
#endif

/* FPU fence to synchronize the FPU and integer core in Snitch. */
inline void snrt_fpu_fence() {
unsigned tmp;
__asm__ volatile(
"fmv.x.w %0, fa0\n"
"mv %0, %0\n"
: "+r"(tmp)::"memory");
}

/* Synch-secure double to uint64 conversion functions. */
static inline uint64_t asuint64(double f) {
uint64_t result;
snrt_fpu_fence();
result = *(uint64_t *)&f;
return result;
}

/* Synch-secure float to uint conversion functions. */
static inline uint64_t asuint(float f) {
uint32_t result;
snrt_fpu_fence();
result = *(uint32_t *)&f;
return result;
}

/* Synch-secure uint64 to double conversion functions. */
static inline double asdouble(uint64_t i) {
double result;
snrt_fpu_fence();
result = *(double *)&i;
return result;
}

/* Synch-secure uint to float conversion functions. */
static inline float asfloat(uint32_t i) {
float result;
snrt_fpu_fence();
result = *(float *)&i;
return result;
}

/* Evaluate an expression as the specified type. With standard excess
precision handling a type cast or assignment is enough (with
-ffloat-store an assignment is required, in old compilers argument
Expand Down Expand Up @@ -187,10 +228,12 @@ static inline void fp_force_evall(long double x)
} \
} while(0)

#define asuint(f) ((union{float _f; uint32_t _i;}){f})._i
#define asfloat(i) ((union{uint32_t _i; float _f;}){i})._f
#define asuint64(f) ((union{double _f; uint64_t _i;}){f})._i
#define asdouble(i) ((union{uint64_t _i; double _f;}){i})._f
// Unsafe in Snitch due to the decoupled FPU and integer
// arithmetic units. Use at your own risk.
#define asuint_unsafe(f) ((union{float _f; uint32_t _i;}){f})._i
#define asfloat_unsafe(i) ((union{uint32_t _i; float _f;}){i})._f
#define asuint64_unsafe(f) ((union{double _f; uint64_t _i;}){f})._i
#define asdouble_unsafe(i) ((union{uint64_t _i; double _f;}){i})._f

#define EXTRACT_WORDS(hi,lo,d) \
do { \
Expand Down

0 comments on commit c26197a

Please sign in to comment.