nanohub: lib: add several missing builtins

Test: build
Change-Id: I33d4200510bcf971bed7ad8caa6cc72ab00d3356
Signed-off-by: Ben Fennema <fennema@google.com>
diff --git a/firmware/lib/builtins/Android.mk b/firmware/lib/builtins/Android.mk
index aa8663c..b43bdb2 100644
--- a/firmware/lib/builtins/Android.mk
+++ b/firmware/lib/builtins/Android.mk
@@ -31,6 +31,10 @@
     umoddi3.c               \
     aeabi_f2d.c             \
     aeabi_llsl.c            \
+    aeabi_llsr.c            \
+    aeabi_ul2f.c            \
+    aeabi_l2f.c             \
+    aeabi_f2ulz.c           \
 
 LOCAL_C_INCLUDES = $(LOCAL_PATH)
 LOCAL_EXPORT_C_INCLUDE_DIRS := \
diff --git a/firmware/lib/builtins/aeabi_f2ulz.c b/firmware/lib/builtins/aeabi_f2ulz.c
new file mode 100644
index 0000000..a6413a7
--- /dev/null
+++ b/firmware/lib/builtins/aeabi_f2ulz.c
@@ -0,0 +1,27 @@
+/* ===-- fixunssfdi.c - Implement __fixunssfdi -----------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+du_int __aeabi_f2ulz(float a);
+
+/* Support for systems that have hardware floating-point; can set the invalid
+ * flag as a side-effect of computation.
+ */
+
+du_int
+__aeabi_f2ulz(float a)
+{
+    if (a <= 0.0f) return 0;
+    float da = a;
+    su_int high = da / 4294967296.f;               /* da / 0x1p32f; */
+    su_int low = da - (float)high * 4294967296.f; /* high * 0x1p32f; */
+    return ((du_int)high << 32) | low;
+}
diff --git a/firmware/lib/builtins/aeabi_l2f.c b/firmware/lib/builtins/aeabi_l2f.c
new file mode 100644
index 0000000..63d832f
--- /dev/null
+++ b/firmware/lib/builtins/aeabi_l2f.c
@@ -0,0 +1,80 @@
+/*===-- floatdisf.c - Implement __floatdisf -------------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===
+ *
+ * This file implements __floatdisf for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+/* Returns: convert a to a float, rounding toward even.*/
+
+/* Assumption: float is a IEEE 32 bit floating point type
+ *             di_int is a 64 bit integral type
+ */
+
+/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+
+#include "int_lib.h"
+
+float __aeabi_l2f(di_int a);
+
+float
+__aeabi_l2f(di_int a)
+{
+    if (a == 0)
+        return 0.0F;
+    const unsigned N = sizeof(di_int) * CHAR_BIT;
+    const di_int s = a >> (N-1);
+    a = (a ^ s) - s;
+    int sd = N - __builtin_clzll(a);  /* number of significant digits */
+    int e = sd - 1;             /* exponent */
+    if (sd > FLT_MANT_DIG)
+    {
+        /*  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+         *  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+         *                                                12345678901234567890123456
+         *  1 = msb 1 bit
+         *  P = bit FLT_MANT_DIG-1 bits to the right of 1
+         *  Q = bit FLT_MANT_DIG bits to the right of 1
+         *  R = "or" of all bits to the right of Q
+         */
+        switch (sd)
+        {
+        case FLT_MANT_DIG + 1:
+            a <<= 1;
+            break;
+        case FLT_MANT_DIG + 2:
+            break;
+        default:
+            a = ((du_int)a >> (sd - (FLT_MANT_DIG+2))) |
+                ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
+        };
+        /* finish: */
+        a |= (a & 4) != 0;  /* Or P into R */
+        ++a;  /* round - this step may add a significant bit */
+        a >>= 2;  /* dump Q and R */
+        /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
+        if (a & ((du_int)1 << FLT_MANT_DIG))
+        {
+            a >>= 1;
+            ++e;
+        }
+        /* a is now rounded to FLT_MANT_DIG bits */
+    }
+    else
+    {
+        a <<= (FLT_MANT_DIG - sd);
+        /* a is now rounded to FLT_MANT_DIG bits */
+    }
+    float_bits fb;
+    fb.u = ((su_int)s & 0x80000000) |  /* sign */
+           ((e + 127) << 23)       |  /* exponent */
+           ((su_int)a & 0x007FFFFF);   /* mantissa */
+    return fb.f;
+}
diff --git a/firmware/lib/builtins/aeabi_llsr.c b/firmware/lib/builtins/aeabi_llsr.c
new file mode 100644
index 0000000..2f0ba6b
--- /dev/null
+++ b/firmware/lib/builtins/aeabi_llsr.c
@@ -0,0 +1,43 @@
+/* ===-- lshrdi3.c - Implement __lshrdi3 -----------------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __lshrdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: logical a >> b */
+
+/* Precondition:  0 <= b < bits_in_dword */
+
+di_int __aeabi_llsr(di_int a, si_int b);
+
+di_int
+__aeabi_llsr(di_int a, si_int b)
+{
+    const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
+    udwords input;
+    udwords result;
+    input.all = a;
+    if (b & bits_in_word)  /* bits_in_word <= b < bits_in_dword */
+    {
+        result.s.high = 0;
+        result.s.low = input.s.high >> (b - bits_in_word);
+    }
+    else  /* 0 <= b < bits_in_word */
+    {
+        if (b == 0)
+            return a;
+        result.s.high  = input.s.high >> b;
+        result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b);
+    }
+    return result.all;
+}
diff --git a/firmware/lib/builtins/aeabi_ul2f.c b/firmware/lib/builtins/aeabi_ul2f.c
new file mode 100644
index 0000000..80734db
--- /dev/null
+++ b/firmware/lib/builtins/aeabi_ul2f.c
@@ -0,0 +1,77 @@
+/*===-- floatundisf.c - Implement __floatundisf ---------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __floatundisf for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+/* Returns: convert a to a float, rounding toward even. */
+
+/* Assumption: float is a IEEE 32 bit floating point type
+ *            du_int is a 64 bit integral type
+ */
+
+/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+
+#include "int_lib.h"
+
+float __aeabi_ul2f(du_int a);
+
+float
+__aeabi_ul2f(du_int a)
+{
+    if (a == 0)
+        return 0.0F;
+    const unsigned N = sizeof(du_int) * CHAR_BIT;
+    int sd = N - __builtin_clzll(a);  /* number of significant digits */
+    int e = sd - 1;             /* 8 exponent */
+    if (sd > FLT_MANT_DIG)
+    {
+        /*  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+         *  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+         *                                                12345678901234567890123456
+         *  1 = msb 1 bit
+         *  P = bit FLT_MANT_DIG-1 bits to the right of 1
+         *  Q = bit FLT_MANT_DIG bits to the right of 1
+         *  R = "or" of all bits to the right of Q
+         */
+        switch (sd)
+        {
+        case FLT_MANT_DIG + 1:
+            a <<= 1;
+            break;
+        case FLT_MANT_DIG + 2:
+            break;
+        default:
+            a = (a >> (sd - (FLT_MANT_DIG+2))) |
+                ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
+        };
+        /* finish: */
+        a |= (a & 4) != 0;  /* Or P into R */
+        ++a;  /* round - this step may add a significant bit */
+        a >>= 2;  /* dump Q and R */
+        /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
+        if (a & ((du_int)1 << FLT_MANT_DIG))
+        {
+            a >>= 1;
+            ++e;
+        }
+        /* a is now rounded to FLT_MANT_DIG bits */
+    }
+    else
+    {
+        a <<= (FLT_MANT_DIG - sd);
+        /* a is now rounded to FLT_MANT_DIG bits */
+    }
+    float_bits fb;
+    fb.u = ((e + 127) << 23)       |  /* exponent */
+           ((su_int)a & 0x007FFFFF);  /* mantissa */
+    return fb.f;
+}
diff --git a/firmware/lib/builtins/int_lib.h b/firmware/lib/builtins/int_lib.h
index 3d968a8..fddef7f 100644
--- a/firmware/lib/builtins/int_lib.h
+++ b/firmware/lib/builtins/int_lib.h
@@ -16,7 +16,8 @@
 #ifndef INT_LIB_H
 #define INT_LIB_H
 
-#define CHAR_BIT 8
+#define FLT_MANT_DIG    __FLT_MANT_DIG__
+#define CHAR_BIT        8
 
 typedef unsigned su_int;
 typedef int si_int;
@@ -44,6 +45,12 @@
     } s;
 } udwords;
 
+typedef union
+{
+    su_int u;
+    float f;
+} float_bits;
+
 /* Assumption: Signed integral is 2's complement. */
 /* Assumption: Right shift of signed negative is arithmetic shift. */
 
diff --git a/firmware/lib/lib.mk b/firmware/lib/lib.mk
index 41d84ee..b26fc9f 100644
--- a/firmware/lib/lib.mk
+++ b/firmware/lib/lib.mk
@@ -84,4 +84,8 @@
 SRCS += $(BUILTINS_PATH)/umoddi3.c
 SRCS += $(BUILTINS_PATH)/aeabi_f2d.c
 SRCS += $(BUILTINS_PATH)/aeabi_llsl.c
+SRCS += $(BUILTINS_PATH)/aeabi_llsr.c
+SRCS += $(BUILTINS_PATH)/aeabi_ul2f.c
+SRCS += $(BUILTINS_PATH)/aeabi_l2f.c
+SRCS += $(BUILTINS_PATH)/aeabi_f2ulz.c
 CFLAGS += -I$(BUILTINS_PATH)