From dcca95ebeef7ad047b437c7e65bcd2d33784cae4 Mon Sep 17 00:00:00 2001
From: Kimplul <kimi.h.kuparinen@gmail.com>
Date: Sun, 14 Jul 2024 14:46:40 +0300
Subject: add float + double instead of just double

---
 include/ejit/ejit.h |  50 ++++++++++--
 src/common.h        |  24 +++++-
 src/ejit.c          | 158 ++++++++++++++++++++++++++++++++++---
 src/interp.c        | 220 +++++++++++++++++++++++++++++++++++++++-------------
 tests/absr_d.c      |  22 ++++++
 tests/absr_f.c      |  12 +--
 tests/addr_d.c      |  24 ++++++
 tests/addr_f.c      |  18 +++--
 tests/beqr_d.c      |  37 +++++++++
 tests/beqr_f.c      |  48 +++++++-----
 tests/bgtr_d.c      |  34 ++++++++
 tests/bgtr_f.c      |  39 ++++++----
 tests/bler_d.c      |  34 ++++++++
 tests/bler_f.c      |  39 ++++++----
 tests/bltr_d.c      |  34 ++++++++
 tests/bltr_f.c      |  25 +++---
 tests/bner_d.c      |  37 +++++++++
 tests/bner_f.c      |  45 +++--------
 tests/divr_d.c      |  24 ++++++
 tests/divr_f.c      |  17 ++--
 tests/eqr_d.c       |  26 +++++++
 tests/eqr_f.c       |  18 ++---
 tests/gtr_d.c       |  25 ++++++
 tests/gtr_f.c       |   8 +-
 tests/ldi_d.c       |   2 +-
 tests/ldxi_d.c      |   2 +-
 tests/ldxr_d.c      |   2 +-
 tests/ler_d.c       |  26 +++++++
 tests/ler_f.c       |  14 ++--
 tests/ltr_d.c       |  27 +++++++
 tests/ltr_f.c       |  12 +--
 tests/movi_d.c      |  16 ++++
 tests/movi_f.c      |   4 +-
 tests/movr_d.c      |  19 +++++
 tests/movr_f.c      |   8 +-
 tests/mulr_d.c      |  24 ++++++
 tests/mulr_f.c      |  14 ++--
 tests/negr_d.c      |  25 ++++++
 tests/negr_f.c      |  14 ++--
 tests/ner_d.c       |  25 ++++++
 tests/ner_f.c       |  10 +--
 tests/subr_d.c      |  27 +++++++
 tests/subr_f.c      |  12 +--
 tests/truncr_f_32.c |  29 +++++++
 tests/truncr_f_64.c |  29 +++++++
 45 files changed, 1094 insertions(+), 265 deletions(-)
 create mode 100644 tests/absr_d.c
 create mode 100644 tests/addr_d.c
 create mode 100644 tests/beqr_d.c
 create mode 100644 tests/bgtr_d.c
 create mode 100644 tests/bler_d.c
 create mode 100644 tests/bltr_d.c
 create mode 100644 tests/bner_d.c
 create mode 100644 tests/divr_d.c
 create mode 100644 tests/eqr_d.c
 create mode 100644 tests/gtr_d.c
 create mode 100644 tests/ler_d.c
 create mode 100644 tests/ltr_d.c
 create mode 100644 tests/movi_d.c
 create mode 100644 tests/movr_d.c
 create mode 100644 tests/mulr_d.c
 create mode 100644 tests/negr_d.c
 create mode 100644 tests/ner_d.c
 create mode 100644 tests/subr_d.c
 create mode 100644 tests/truncr_f_32.c
 create mode 100644 tests/truncr_f_64.c

diff --git a/include/ejit/ejit.h b/include/ejit/ejit.h
index 6e42f15..1e2fb3a 100644
--- a/include/ejit/ejit.h
+++ b/include/ejit/ejit.h
@@ -312,17 +312,22 @@ void ejit_escapei_f(struct ejit_func *s, ejit_escape_f_t f, size_t argc,
 void ejit_ret(struct ejit_func *s);
 void ejit_retr(struct ejit_func *s, struct ejit_gpr r0);
 void ejit_retr_f(struct ejit_func *s, struct ejit_fpr r0);
+void ejit_retr_d(struct ejit_func *s, struct ejit_fpr r0);
+
 void ejit_reti(struct ejit_func *s, long i);
-void ejit_reti_f(struct ejit_func *s, double f);
+void ejit_reti_f(struct ejit_func *s, float f);
+void ejit_reti_d(struct ejit_func *s, double f);
 
 void ejit_retval(struct ejit_func *s, struct ejit_gpr r0);
 void ejit_retval_f(struct ejit_func *s, struct ejit_fpr r0);
 
 /* move from r1 to r0 */
 void ejit_movi(struct ejit_func *s, struct ejit_gpr r0, int64_t i);
-void ejit_movi_f(struct ejit_func *s, struct ejit_fpr f0, double i);
+void ejit_movi_f(struct ejit_func *s, struct ejit_fpr f0, float i);
+void ejit_movi_d(struct ejit_func *s, struct ejit_fpr f0, double i);
 void ejit_movr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1);
 void ejit_movr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1);
+void ejit_movr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1);
 
 void ejit_ldi_i8(struct ejit_func *s, struct ejit_gpr r0, void *p);
 void ejit_ldi_i16(struct ejit_func *s, struct ejit_gpr r0, void *p);
@@ -544,11 +549,14 @@ void ejit_addr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
 
 void ejit_addr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
                  struct ejit_fpr r2);
+void ejit_addr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
+                 struct ejit_fpr r2);
 
 void ejit_addi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                int64_t o);
 
 void ejit_absr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1);
+void ejit_absr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1);
 
 void ejit_subr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                struct ejit_gpr r2);
@@ -556,6 +564,9 @@ void ejit_subr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
 void ejit_subr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
                  struct ejit_fpr r2);
 
+void ejit_subr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
+                 struct ejit_fpr r2);
+
 void ejit_subi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                int64_t o);
 
@@ -563,6 +574,8 @@ void ejit_mulr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                struct ejit_gpr r2);
 void ejit_mulr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
                  struct ejit_fpr r2);
+void ejit_mulr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
+                 struct ejit_fpr r2);
 
 void ejit_divr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                struct ejit_gpr r2);
@@ -570,6 +583,8 @@ void ejit_divr_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                  struct ejit_gpr r2);
 void ejit_divr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
                  struct ejit_fpr r2);
+void ejit_divr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
+                 struct ejit_fpr r2);
 
 void ejit_remr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                struct ejit_gpr r2);
@@ -608,16 +623,21 @@ void ejit_xorr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
 void ejit_comr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1);
 void ejit_negr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1);
 void ejit_negr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1);
+void ejit_negr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1);
 
 void ejit_eqr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
               struct ejit_gpr r2);
 void ejit_eqr_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
                 struct ejit_fpr r2);
+void ejit_eqr_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
+                struct ejit_fpr r2);
 
 void ejit_ner(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
               struct ejit_gpr r2);
 void ejit_ner_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
                 struct ejit_fpr r2);
+void ejit_ner_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
+                struct ejit_fpr r2);
 
 void ejit_gtr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
               struct ejit_gpr r2);
@@ -625,6 +645,8 @@ void ejit_gtr_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                 struct ejit_gpr r2);
 void ejit_gtr_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
                 struct ejit_fpr r2);
+void ejit_gtr_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
+                struct ejit_fpr r2);
 
 void ejit_ltr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
               struct ejit_gpr r2);
@@ -632,6 +654,8 @@ void ejit_ltr_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                 struct ejit_gpr r2);
 void ejit_ltr_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
                 struct ejit_fpr r2);
+void ejit_ltr_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
+                struct ejit_fpr r2);
 
 void ejit_ger(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
               struct ejit_gpr r2);
@@ -639,11 +663,20 @@ void ejit_ger_u(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                 struct ejit_gpr r2);
 void ejit_ger_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
                 struct ejit_fpr r2);
+void ejit_ger_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
+                struct ejit_fpr r2);
 
 void ejit_ler(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
               struct ejit_gpr r2);
 void ejit_ler_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
                 struct ejit_fpr r2);
+void ejit_ler_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
+                struct ejit_fpr r2);
+
+void ejit_truncr_f_32(struct ejit_func *s, struct ejit_gpr r0,
+                      struct ejit_fpr r1);
+void ejit_truncr_f_64(struct ejit_func *s, struct ejit_gpr r0,
+                      struct ejit_fpr r1);
 
 void ejit_truncr_d_32(struct ejit_func *s, struct ejit_gpr r0,
                       struct ejit_fpr r1);
@@ -657,12 +690,16 @@ struct ejit_reloc ejit_bner(struct ejit_func *s, struct ejit_gpr r0,
 struct ejit_reloc ejit_bnei(struct ejit_func *s, struct ejit_gpr r0, int64_t o);
 struct ejit_reloc ejit_bner_f(struct ejit_func *s, struct ejit_fpr r0,
                               struct ejit_fpr r1);
+struct ejit_reloc ejit_bner_d(struct ejit_func *s, struct ejit_fpr r0,
+                              struct ejit_fpr r1);
 
 struct ejit_reloc ejit_beqr(struct ejit_func *s, struct ejit_gpr r0,
                             struct ejit_gpr r1);
 struct ejit_reloc ejit_beqi(struct ejit_func *s, struct ejit_gpr r0, int64_t o);
 struct ejit_reloc ejit_beqr_f(struct ejit_func *s, struct ejit_fpr r0,
                               struct ejit_fpr r1);
+struct ejit_reloc ejit_beqr_d(struct ejit_func *s, struct ejit_fpr r0,
+                              struct ejit_fpr r1);
 
 struct ejit_reloc ejit_bger(struct ejit_func *s, struct ejit_gpr r0,
                             struct ejit_gpr r1);
@@ -681,6 +718,8 @@ struct ejit_reloc ejit_bler_u(struct ejit_func *s, struct ejit_gpr r0,
                               struct ejit_gpr r1);
 struct ejit_reloc ejit_bler_f(struct ejit_func *s, struct ejit_fpr r0,
                               struct ejit_fpr r1);
+struct ejit_reloc ejit_bler_d(struct ejit_func *s, struct ejit_fpr r0,
+                              struct ejit_fpr r1);
 
 struct ejit_reloc ejit_blei(struct ejit_func *s, struct ejit_gpr r0, int64_t o);
 struct ejit_reloc ejit_blei_u(struct ejit_func *s, struct ejit_gpr r0,
@@ -692,6 +731,8 @@ struct ejit_reloc ejit_bgtr_u(struct ejit_func *s, struct ejit_gpr r0,
                               struct ejit_gpr r1);
 struct ejit_reloc ejit_bgtr_f(struct ejit_func *s, struct ejit_fpr r0,
                               struct ejit_fpr r1);
+struct ejit_reloc ejit_bgtr_d(struct ejit_func *s, struct ejit_fpr r0,
+                              struct ejit_fpr r1);
 
 struct ejit_reloc ejit_bgti(struct ejit_func *s, struct ejit_gpr r0, int64_t o);
 struct ejit_reloc ejit_bgti_u(struct ejit_func *s, struct ejit_gpr r0,
@@ -703,14 +744,13 @@ struct ejit_reloc ejit_bltr_u(struct ejit_func *s, struct ejit_gpr r0,
                               struct ejit_gpr r1);
 struct ejit_reloc ejit_bltr_f(struct ejit_func *s, struct ejit_fpr r0,
                               struct ejit_fpr r1);
+struct ejit_reloc ejit_bltr_d(struct ejit_func *s, struct ejit_fpr r0,
+                              struct ejit_fpr r1);
 
 struct ejit_reloc ejit_blti(struct ejit_func *s, struct ejit_gpr r0, int64_t o);
 struct ejit_reloc ejit_blti_u(struct ejit_func *s, struct ejit_gpr r0,
                               int64_t o);
 
-struct ejit_reloc ejit_bltgtr_f(struct ejit_func *s, struct ejit_fpr r0,
-                                struct ejit_fpr r1);
-
 struct ejit_reloc ejit_jmp(struct ejit_func *s);
 struct ejit_reloc ejit_jmpr(struct ejit_func *s, struct ejit_gpr r0);
 
diff --git a/src/common.h b/src/common.h
index 1e08961..c646288 100644
--- a/src/common.h
+++ b/src/common.h
@@ -7,8 +7,10 @@
 enum ejit_opcode {
 	MOVI,
 	MOVI_F,
+	MOVI_D,
 	MOVR,
 	MOVR_F,
+	MOVR_D,
 
 	LDI8,
 	LDI16,
@@ -73,20 +75,25 @@ enum ejit_opcode {
 
 	ADDR,
 	ADDR_F,
+	ADDR_D,
 	ADDI,
 
 	ABSR_F,
+	ABSR_D,
 
 	SUBR,
 	SUBR_F,
+	SUBR_D,
 	SUBI,
 
 	MULR,
 	MULR_F,
+	MULR_D,
 
 	DIVR,
 	DIVR_U,
 	DIVR_F,
+	DIVR_D,
 
 	REMR,
 	REMR_U,
@@ -94,6 +101,7 @@ enum ejit_opcode {
 	COMR,
 	NEGR,
 	NEGR_F,
+	NEGR_D,
 
 	LSHI,
 	LSHR,
@@ -113,6 +121,8 @@ enum ejit_opcode {
 
 	TRUNCR_D_32,
 	TRUNCR_D_64,
+	TRUNCR_F_32,
+	TRUNCR_F_64,
 
 	EQR,
 	NER,
@@ -125,20 +135,27 @@ enum ejit_opcode {
 	NER_F,
 	GTR_F,
 	GER_F,
+	EQR_D,
+	NER_D,
+	GTR_D,
+	GER_D,
 
 	BNER,
 	BNEI,
 	BNER_F,
+	BNER_D,
 
 	BEQR,
 	BEQI,
 	BEQR_F,
+	BEQR_D,
 
 	BGER,
 	BGER_U,
 	BGEI,
 	BGEI_U,
 	BGER_F,
+	BGER_D,
 
 	BLEI,
 	BLEI_U,
@@ -148,12 +165,11 @@ enum ejit_opcode {
 	BGTI,
 	BGTI_U,
 	BGTR_F,
+	BGTR_D,
 
 	BLTI,
 	BLTI_U,
 
-	BLTGTR_F,
-
 	JMP,
 	JMPR,
 
@@ -179,10 +195,13 @@ enum ejit_opcode {
 	RETR,
 	RETI,
 	RETR_F,
+	RETR_D,
 	RETI_F,
+	RETI_D,
 
 	RETVAL,
 	RETVAL_F,
+	RETVAL_D,
 
 	START,
 	END,
@@ -203,6 +222,7 @@ struct ejit_insn {
 		void *p;
 		int64_t o;
 		double d;
+		float f;
 	};
 };
 
diff --git a/src/ejit.c b/src/ejit.c
index 02446ea..c6b8f72 100644
--- a/src/ejit.c
+++ b/src/ejit.c
@@ -27,6 +27,13 @@ static void emit_insn_p(struct ejit_func *f, enum ejit_opcode op, size_t r0,
 }
 
 static void emit_insn_f(struct ejit_func *f, enum ejit_opcode op, size_t r0,
+                        size_t r1, float d)
+{
+	struct ejit_insn i = {.op = op, .r0 = r0, .r1 = r1, .f = d};
+	vec_append(&f->insns, &i);
+}
+
+static void emit_insn_d(struct ejit_func *f, enum ejit_opcode op, size_t r0,
                         size_t r1, double d)
 {
 	struct ejit_insn i = {.op = op, .r0 = r0, .r1 = r1, .d = d};
@@ -484,16 +491,26 @@ void ejit_retr_f(struct ejit_func *s, struct ejit_fpr r0)
 	emit_insn_r(s, RETR_F, r0.f, 0, 0);
 }
 
+void ejit_retr_d(struct ejit_func *s, struct ejit_fpr r0)
+{
+	emit_insn_r(s, RETR_D, r0.f, 0, 0);
+}
+
 void ejit_reti(struct ejit_func *s, int64_t i)
 {
 	emit_insn_i(s, RETI, 0, 0, i);
 }
 
-void ejit_reti_f(struct ejit_func *s, double f)
+void ejit_reti_f(struct ejit_func *s, float f)
 {
 	emit_insn_f(s, RETI_F, 0, 0, f);
 }
 
+void ejit_reti_d(struct ejit_func *s, double f)
+{
+	emit_insn_d(s, RETI_F, 0, 0, f);
+}
+
 void ejit_extr_8(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1)
 {
 	emit_insn_i(s, EXTR8, r0.r, r1.r, 0);
@@ -536,6 +553,12 @@ void ejit_addr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
 	emit_insn_r(s, ADDR_F, r0.f, r1.f, r2.f);
 }
 
+void ejit_addr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
+                 struct ejit_fpr r2)
+{
+	emit_insn_r(s, ADDR_D, r0.f, r1.f, r2.f);
+}
+
 void ejit_addi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                int64_t o)
 {
@@ -547,6 +570,11 @@ void ejit_absr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1)
 	emit_insn_i(s, ABSR_F, r0.f, r1.f, 0);
 }
 
+void ejit_absr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1)
+{
+	emit_insn_i(s, ABSR_D, r0.f, r1.f, 0);
+}
+
 void ejit_subr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                struct ejit_gpr r2)
 {
@@ -559,6 +587,12 @@ void ejit_subr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
 	emit_insn_r(s, SUBR_F, r0.f, r1.f, r2.f);
 }
 
+void ejit_subr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
+                 struct ejit_fpr r2)
+{
+	emit_insn_r(s, SUBR_D, r0.f, r1.f, r2.f);
+}
+
 void ejit_subi(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                long o)
 {
@@ -577,6 +611,12 @@ void ejit_mulr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
 	emit_insn_r(s, MULR_F, r0.f, r1.f, r2.f);
 }
 
+void ejit_mulr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
+                 struct ejit_fpr r2)
+{
+	emit_insn_r(s, MULR_D, r0.f, r1.f, r2.f);
+}
+
 void ejit_divr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                struct ejit_gpr r2)
 {
@@ -595,6 +635,12 @@ void ejit_divr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
 	emit_insn_r(s, DIVR_F, r0.f, r1.f, r2.f);
 }
 
+void ejit_divr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1,
+                 struct ejit_fpr r2)
+{
+	emit_insn_r(s, DIVR_D, r0.f, r1.f, r2.f);
+}
+
 void ejit_remr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
                struct ejit_gpr r2)
 {
@@ -694,16 +740,26 @@ void ejit_negr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1)
 	emit_insn_i(s, NEGR_F, r0.f, r1.f, 0);
 }
 
+void ejit_negr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1)
+{
+	emit_insn_i(s, NEGR_D, r0.f, r1.f, 0);
+}
+
 void ejit_movi(struct ejit_func *s, struct ejit_gpr r0, int64_t o)
 {
 	emit_insn_i(s, MOVI, r0.r, 0, o);
 }
 
-void ejit_movi_f(struct ejit_func *s, struct ejit_fpr r0, double o)
+void ejit_movi_f(struct ejit_func *s, struct ejit_fpr r0, float o)
 {
 	emit_insn_f(s, MOVI_F, r0.f, 0, o);
 }
 
+void ejit_movi_d(struct ejit_func *s, struct ejit_fpr r0, double o)
+{
+	emit_insn_d(s, MOVI_D, r0.f, 0, o);
+}
+
 void ejit_movr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1)
 {
 	if (r0.r == r1.r)
@@ -720,6 +776,14 @@ void ejit_movr_f(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1)
 	emit_insn_i(s, MOVR_F, r0.f, r1.f, 0);
 }
 
+void ejit_movr_d(struct ejit_func *s, struct ejit_fpr r0, struct ejit_fpr r1)
+{
+	if (r0.f == r1.f)
+		return;
+
+	emit_insn_i(s, MOVR_D, r0.f, r1.f, 0);
+}
+
 void ejit_eqr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
               struct ejit_gpr r2)
 {
@@ -732,6 +796,12 @@ void ejit_eqr_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
 	emit_insn_r(s, EQR_F, r0.r, r1.f, r2.f);
 }
 
+void ejit_eqr_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
+                struct ejit_fpr r2)
+{
+	emit_insn_r(s, EQR_D, r0.r, r1.f, r2.f);
+}
+
 void ejit_ner(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
               struct ejit_gpr r2)
 {
@@ -744,6 +814,12 @@ void ejit_ner_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
 	emit_insn_r(s, NER_F, r0.r, r1.f, r2.f);
 }
 
+void ejit_ner_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
+                struct ejit_fpr r2)
+{
+	emit_insn_r(s, NER_D, r0.r, r1.f, r2.f);
+}
+
 void ejit_gtr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
               struct ejit_gpr r2)
 {
@@ -762,6 +838,12 @@ void ejit_gtr_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
 	emit_insn_r(s, GTR_F, r0.r, r1.f, r2.f);
 }
 
+void ejit_gtr_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
+                struct ejit_fpr r2)
+{
+	emit_insn_r(s, GTR_D, r0.r, r1.f, r2.f);
+}
+
 void ejit_ltr(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
               struct ejit_gpr r2)
 {
@@ -780,6 +862,12 @@ void ejit_ltr_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
 	emit_insn_r(s, GTR_F, r0.r, r2.f, r1.f);
 }
 
+void ejit_ltr_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
+                struct ejit_fpr r2)
+{
+	emit_insn_r(s, GTR_D, r0.r, r2.f, r1.f);
+}
+
 void ejit_ger(struct ejit_func *s, struct ejit_gpr r0, struct ejit_gpr r1,
               struct ejit_gpr r2)
 {
@@ -816,6 +904,12 @@ void ejit_ler_f(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
 	emit_insn_r(s, GER_F, r0.r, r2.f, r1.f);
 }
 
+void ejit_ler_d(struct ejit_func *s, struct ejit_gpr r0, struct ejit_fpr r1,
+                struct ejit_fpr r2)
+{
+	emit_insn_r(s, GER_D, r0.r, r2.f, r1.f);
+}
+
 void ejit_truncr_d_32(struct ejit_func *s, struct ejit_gpr r0,
                       struct ejit_fpr r1)
 {
@@ -828,6 +922,18 @@ void ejit_truncr_d_64(struct ejit_func *s, struct ejit_gpr r0,
 	emit_insn_i(s, TRUNCR_D_64, r0.r, r1.f, 0);
 }
 
+void ejit_truncr_f_32(struct ejit_func *s, struct ejit_gpr r0,
+                      struct ejit_fpr r1)
+{
+	emit_insn_i(s, TRUNCR_F_32, r0.r, r1.f, 0);
+}
+
+void ejit_truncr_f_64(struct ejit_func *s, struct ejit_gpr r0,
+                      struct ejit_fpr r1)
+{
+	emit_insn_i(s, TRUNCR_F_64, r0.r, r1.f, 0);
+}
+
 struct ejit_reloc ejit_bner(struct ejit_func *s, struct ejit_gpr r0,
                             struct ejit_gpr r1)
 {
@@ -851,6 +957,14 @@ struct ejit_reloc ejit_bner_f(struct ejit_func *s, struct ejit_fpr r0,
 	return (struct ejit_reloc){.insn = addr};
 }
 
+struct ejit_reloc ejit_bner_d(struct ejit_func *s, struct ejit_fpr r0,
+                              struct ejit_fpr r1)
+{
+	size_t addr = vec_len(&s->insns);
+	emit_insn_r(s, BNER_D, 0, r0.f, r1.f);
+	return (struct ejit_reloc){.insn = addr};
+}
+
 struct ejit_reloc ejit_beqr(struct ejit_func *s, struct ejit_gpr r0,
                             struct ejit_gpr r1)
 {
@@ -874,6 +988,14 @@ struct ejit_reloc ejit_beqr_f(struct ejit_func *s, struct ejit_fpr r0,
 	return (struct ejit_reloc){.insn = addr};
 }
 
+struct ejit_reloc ejit_beqr_d(struct ejit_func *s, struct ejit_fpr r0,
+                              struct ejit_fpr r1)
+{
+	size_t addr = vec_len(&s->insns);
+	emit_insn_r(s, BEQR_D, 0, r0.f, r1.f);
+	return (struct ejit_reloc){.insn = addr};
+}
+
 struct ejit_reloc ejit_bger(struct ejit_func *s, struct ejit_gpr r0,
                             struct ejit_gpr r1)
 {
@@ -937,6 +1059,14 @@ struct ejit_reloc ejit_bler_f(struct ejit_func *s, struct ejit_fpr r0,
 	return (struct ejit_reloc){.insn = addr};
 }
 
+struct ejit_reloc ejit_bler_d(struct ejit_func *s, struct ejit_fpr r0,
+                              struct ejit_fpr r1)
+{
+	size_t addr = vec_len(&s->insns);
+	emit_insn_r(s, BGER_D, 0, r1.f, r0.f);
+	return (struct ejit_reloc){.insn = addr};
+}
+
 struct ejit_reloc ejit_blei(struct ejit_func *s, struct ejit_gpr r0, int64_t o)
 {
 	size_t addr = vec_len(&s->insns);
@@ -991,6 +1121,14 @@ struct ejit_reloc ejit_bgtr_f(struct ejit_func *s, struct ejit_fpr r0,
 	return (struct ejit_reloc){.insn = addr};
 }
 
+struct ejit_reloc ejit_bgtr_d(struct ejit_func *s, struct ejit_fpr r0,
+                              struct ejit_fpr r1)
+{
+	size_t addr = vec_len(&s->insns);
+	emit_insn_r(s, BGTR_D, 0, r0.f, r1.f);
+	return (struct ejit_reloc){.insn = addr};
+}
+
 struct ejit_reloc ejit_bltr(struct ejit_func *s, struct ejit_gpr r0,
                             struct ejit_gpr r1)
 {
@@ -1015,26 +1153,26 @@ struct ejit_reloc ejit_bltr_f(struct ejit_func *s, struct ejit_fpr r0,
 	return (struct ejit_reloc){.insn = addr};
 }
 
-struct ejit_reloc ejit_blti(struct ejit_func *s, struct ejit_gpr r0, int64_t o)
+struct ejit_reloc ejit_bltr_d(struct ejit_func *s, struct ejit_fpr r0,
+                              struct ejit_fpr r1)
 {
 	size_t addr = vec_len(&s->insns);
-	emit_insn_i(s, BLTI, 0, r0.r, o);
+	emit_insn_r(s, BGTR_D, 0, r1.f, r0.f);
 	return (struct ejit_reloc){.insn = addr};
 }
 
-struct ejit_reloc ejit_blti_u(struct ejit_func *s, struct ejit_gpr r0,
-                              int64_t o)
+struct ejit_reloc ejit_blti(struct ejit_func *s, struct ejit_gpr r0, int64_t o)
 {
 	size_t addr = vec_len(&s->insns);
-	emit_insn_i(s, BLTI_U, 0, r0.r, o);
+	emit_insn_i(s, BLTI, 0, r0.r, o);
 	return (struct ejit_reloc){.insn = addr};
 }
 
-struct ejit_reloc ejit_bltgtr_f(struct ejit_func *s, struct ejit_fpr r0,
-                                struct ejit_fpr r1)
+struct ejit_reloc ejit_blti_u(struct ejit_func *s, struct ejit_gpr r0,
+                              int64_t o)
 {
 	size_t addr = vec_len(&s->insns);
-	emit_insn_r(s, BLTGTR_F, 0, r0.f, r1.f);
+	emit_insn_i(s, BLTI_U, 0, r0.r, o);
 	return (struct ejit_reloc){.insn = addr};
 }
 
diff --git a/src/interp.c b/src/interp.c
index 8462112..293da46 100644
--- a/src/interp.c
+++ b/src/interp.c
@@ -11,8 +11,10 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	static void *labels[OPCODE_COUNT] = {
 		[MOVI] = &&MOVI,
 		[MOVI_F] = &&MOVI_F,
+		[MOVI_D] = &&MOVI_D,
 		[MOVR] = &&MOVR,
 		[MOVR_F] = &&MOVR_F,
+		[MOVR_D] = &&MOVR_D,
 
 		[EXTR8] = &&EXTR8,
 		[EXTR16] = &&EXTR16,
@@ -23,20 +25,25 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 
 		[ADDR] = &&ADDR,
 		[ADDR_F] = &&ADDR_F,
+		[ADDR_D] = &&ADDR_D,
 		[ADDI] = &&ADDI,
 
 		[ABSR_F] = &&ABSR_F,
+		[ABSR_D] = &&ABSR_D,
 
 		[SUBR] = &&SUBR,
 		[SUBR_F] = &&SUBR_F,
+		[SUBR_D] = &&SUBR_D,
 		[SUBI] = &&SUBI,
 
 		[MULR] = &&MULR,
 		[MULR_F] = &&MULR_F,
+		[MULR_D] = &&MULR_D,
 
 		[DIVR] = &&DIVR,
 		[DIVR_U] = &&DIVR_U,
 		[DIVR_F] = &&DIVR_F,
+		[DIVR_D] = &&DIVR_D,
 
 		[REMR] = &&REMR,
 		[REMR_U] = &&REMR_U,
@@ -60,20 +67,25 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 		[COMR] = &&COMR,
 		[NEGR] = &&NEGR,
 		[NEGR_F] = &&NEGR_F,
+		[NEGR_D] = &&NEGR_D,
 
 		[EQR] = &&EQR,
 		[EQR_F] = &&EQR_F,
+		[EQR_D] = &&EQR_D,
 
 		[NER] = &&NER,
 		[NER_F] = &&NER_F,
+		[NER_D] = &&NER_D,
 
 		[GTR] = &&GTR,
 		[GTR_U] = &&GTR_U,
 		[GTR_F] = &&GTR_F,
+		[GTR_D] = &&GTR_D,
 
 		[GER] = &&GER,
 		[GER_U] = &&GER_U,
 		[GER_F] = &&GER_F,
+		[GER_D] = &&GER_D,
 
 		[STI8] = &&STI8,
 		[STI16] = &&STI16,
@@ -131,20 +143,25 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 
 		[TRUNCR_D_32] = &&TRUNCR_D_32,
 		[TRUNCR_D_64] = &&TRUNCR_D_64,
+		[TRUNCR_F_32] = &&TRUNCR_F_32,
+		[TRUNCR_F_64] = &&TRUNCR_F_64,
 
 		[BNER] = &&BNER,
 		[BNEI] = &&BNEI,
 		[BNER_F] = &&BNER_F,
+		[BNER_D] = &&BNER_D,
 
 		[BEQR] = &&BEQR,
 		[BEQI] = &&BEQI,
 		[BEQR_F] = &&BEQR_F,
+		[BEQR_D] = &&BEQR_D,
 
 		[BGER] = &&BGER,
 		[BGER_U] = &&BGER_U,
 		[BGEI] = &&BGEI,
 		[BGEI_U] = &&BGEI_U,
 		[BGER_F] = &&BGER_F,
+		[BGER_D] = &&BGER_D,
 
 		[BLEI] = &&BLEI,
 		[BLEI_U] = &&BLEI_U,
@@ -154,12 +171,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 		[BGTI] = &&BGTI,
 		[BGTI_U] = &&BGTI_U,
 		[BGTR_F] = &&BGTR_F,
+		[BGTR_D] = &&BGTR_D,
 
 		[BLTI] = &&BLTI,
 		[BLTI_U] = &&BLTI_U,
 
-		[BLTGTR_F] = &&BLTGTR_F,
-
 		[JMP] = &&JMP,
 		[JMPR] = &&JMPR,
 
@@ -172,9 +188,12 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 		[RETI] = &&RETI,
 		[RETR_F] = &&RETR_F,
 		[RETI_F] = &&RETI_F,
+		[RETR_D] = &&RETR_D,
+		[RETI_D] = &&RETI_D,
 
 		[RETVAL] = &&RETVAL,
 		[RETVAL_F] = &&RETVAL_F,
+		[RETVAL_D] = &&RETVAL_D,
 
 		[ARG] = &&ARG,
 		[ARG_I] = &&ARG_I,
@@ -205,8 +224,12 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	vec_reserve(&state->gprs, prev_gprs + f->gpr);
 	vec_reserve(&state->fprs, prev_fprs + f->fpr);
 
+	union fpr {
+		double d;
+		float f;
+	};
 	long *gpr = ((long *)state->gprs.buf) + prev_gprs;
-	double *fpr = ((double *)state->fprs.buf) + prev_fprs;
+	union fpr *fpr = ((union fpr *)state->fprs.buf) + prev_fprs;
 
 	struct ejit_insn *insns = f->insns.buf;
 
@@ -234,7 +257,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(MOVI_F);
-	fpr[i.r0] = i.d;
+	fpr[i.r0].f = i.f;
+	DISPATCH();
+
+	DO(MOVI_D);
+	fpr[i.r0].d = i.d;
 	DISPATCH();
 
 	DO(MOVR);
@@ -242,7 +269,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(MOVR_F);
-	fpr[i.r0] = fpr[i.r1];
+	fpr[i.r0].f = fpr[i.r1].f;
+	DISPATCH();
+
+	DO(MOVR_D);
+	fpr[i.r0].d = fpr[i.r1].d;
 	DISPATCH();
 
 	DO(EXTR8);
@@ -274,7 +305,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(ADDR_F);
-	fpr[i.r0] = fpr[i.r1] + fpr[i.r2];
+	fpr[i.r0].f = fpr[i.r1].f + fpr[i.r2].f;
+	DISPATCH();
+
+	DO(ADDR_D);
+	fpr[i.r0].d = fpr[i.r1].d + fpr[i.r2].d;
 	DISPATCH();
 
 	DO(ADDI);
@@ -282,7 +317,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(ABSR_F);
-	fpr[i.r0] = fabs(fpr[i.r1]);
+	fpr[i.r0].f = fabs(fpr[i.r1].f);
+	DISPATCH();
+
+	DO(ABSR_D);
+	fpr[i.r0].d = fabs(fpr[i.r1].d);
 	DISPATCH();
 
 	DO(SUBR);
@@ -290,7 +329,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(SUBR_F);
-	fpr[i.r0] = fpr[i.r1] - fpr[i.r2];
+	fpr[i.r0].f = fpr[i.r1].f - fpr[i.r2].f;
+	DISPATCH();
+
+	DO(SUBR_D);
+	fpr[i.r0].d = fpr[i.r1].d - fpr[i.r2].d;
 	DISPATCH();
 
 	DO(SUBI);
@@ -302,7 +345,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(MULR_F);
-	fpr[i.r0] = fpr[i.r1] * fpr[i.r2];
+	fpr[i.r0].f = fpr[i.r1].f * fpr[i.r2].f;
+	DISPATCH();
+
+	DO(MULR_D);
+	fpr[i.r0].d = fpr[i.r1].d * fpr[i.r2].d;
 	DISPATCH();
 
 	DO(DIVR);
@@ -322,7 +369,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(DIVR_F);
-	fpr[i.r0] = fpr[i.r1] / fpr[i.r2];
+	fpr[i.r0].f = fpr[i.r1].f / fpr[i.r2].f;
+	DISPATCH();
+
+	DO(DIVR_D);
+	fpr[i.r0].d = fpr[i.r1].d / fpr[i.r2].d;
 	DISPATCH();
 
 	DO(LSHI);
@@ -382,7 +433,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(NEGR_F);
-	fpr[i.r0] = -fpr[i.r1];
+	fpr[i.r0].f = -fpr[i.r1].f;
+	DISPATCH();
+
+	DO(NEGR_D);
+	fpr[i.r0].d = -fpr[i.r1].d;
 	DISPATCH();
 
 	DO(EQR);
@@ -390,7 +445,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(EQR_F);
-	gpr[i.r0] = fpr[i.r1] == fpr[i.r2];
+	gpr[i.r0] = fpr[i.r1].f == fpr[i.r2].f;
+	DISPATCH();
+
+	DO(EQR_D);
+	gpr[i.r0] = fpr[i.r1].d == fpr[i.r2].d;
 	DISPATCH();
 
 	DO(NER);
@@ -398,7 +457,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(NER_F);
-	gpr[i.r0] = fpr[i.r1] != fpr[i.r2];
+	gpr[i.r0] = fpr[i.r1].f != fpr[i.r2].f;
+	DISPATCH();
+
+	DO(NER_D);
+	gpr[i.r0] = fpr[i.r1].d != fpr[i.r2].d;
 	DISPATCH();
 
 	DO(GTR);
@@ -410,7 +473,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(GTR_F);
-	gpr[i.r0] = fpr[i.r1] > fpr[i.r2];
+	gpr[i.r0] = fpr[i.r1].f > fpr[i.r2].f;
+	DISPATCH();
+
+	DO(GTR_D);
+	gpr[i.r0] = fpr[i.r1].d > fpr[i.r2].d;
 	DISPATCH();
 
 	DO(GER);
@@ -422,7 +489,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(GER_F);
-	gpr[i.r0] = fpr[i.r1] >= fpr[i.r2];
+	gpr[i.r0] = fpr[i.r1].f >= fpr[i.r2].f;
+	DISPATCH();
+
+	DO(GER_D);
+	gpr[i.r0] = fpr[i.r1].d >= fpr[i.r2].d;
 	DISPATCH();
 
 	DO(STI8);
@@ -447,12 +518,12 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 
 	DO(STIF);
 	float *addr = (float *)(i.p);
-	*addr = fpr[i.r0];
+	*addr = fpr[i.r0].f;
 	DISPATCH();
 
 	DO(STID);
 	double *addr = (double *)(i.p);
-	*addr = fpr[i.r0];
+	*addr = fpr[i.r0].d;
 	DISPATCH();
 
 	DO(STXI8);
@@ -477,12 +548,12 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 
 	DO(STXIF);
 	float *addr = (float *)(gpr[i.r1] + i.o);
-	*addr = fpr[i.r0];
+	*addr = fpr[i.r0].f;
 	DISPATCH();
 
 	DO(STXID);
 	double *addr = (double *)(gpr[i.r1] + i.o);
-	*addr = fpr[i.r0];
+	*addr = fpr[i.r0].d;
 	DISPATCH();
 
 	DO(STXR8);
@@ -507,12 +578,12 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 
 	DO(STXRF);
 	float *addr = (float *)(gpr[i.r1] + gpr[i.r2]);
-	*addr = fpr[i.r0];
+	*addr = fpr[i.r0].f;
 	DISPATCH();
 
 	DO(STXRD);
 	double *addr = (double *)(gpr[i.r1] + gpr[i.r2]);
-	*addr = fpr[i.r0];
+	*addr = fpr[i.r0].d;
 	DISPATCH();
 
 	DO(LDI8);
@@ -557,12 +628,12 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 
 	DO(LDIF);
 	float *addr = (float *)i.p;
-	fpr[i.r0] = *addr;
+	fpr[i.r0].f = *addr;
 	DISPATCH();
 
 	DO(LDID);
 	double *addr = (double *)i.p;
-	fpr[i.r0] = *addr;
+	fpr[i.r0].d = *addr;
 	DISPATCH();
 
 	DO(LDXI8);
@@ -607,12 +678,12 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 
 	DO(LDXIF);
 	float *addr = (float *)(gpr[i.r1] + i.o);
-	fpr[i.r0] = *addr;
+	fpr[i.r0].f = *addr;
 	DISPATCH();
 
 	DO(LDXID);
 	double *addr = (double *)(gpr[i.r1] + i.o);
-	fpr[i.r0] = *addr;
+	fpr[i.r0].d = *addr;
 	DISPATCH();
 
 	DO(LDXR8);
@@ -657,20 +728,28 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 
 	DO(LDXRF);
 	float *addr = (float *)(gpr[i.r1] + gpr[i.r2]);
-	fpr[i.r0] = *addr;
+	fpr[i.r0].f = *addr;
 	DISPATCH();
 
 	DO(LDXRD);
 	double *addr = (double *)(gpr[i.r1] + gpr[i.r2]);
-	fpr[i.r0] = *addr;
+	fpr[i.r0].d = *addr;
 	DISPATCH();
 
 	DO(TRUNCR_D_32);
-	gpr[i.r0] = (int32_t)fpr[i.r1];
+	gpr[i.r0] = (int32_t)fpr[i.r1].d;
 	DISPATCH();
 
 	DO(TRUNCR_D_64);
-	gpr[i.r0] = (int64_t)fpr[i.r1];
+	gpr[i.r0] = (int64_t)fpr[i.r1].d;
+	DISPATCH();
+
+	DO(TRUNCR_F_32);
+	gpr[i.r0] = (int32_t)fpr[i.r1].f;
+	DISPATCH();
+
+	DO(TRUNCR_F_64);
+	gpr[i.r0] = (int64_t)fpr[i.r1].f;
 	DISPATCH();
 
 	DO(BNER);
@@ -686,7 +765,13 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(BNER_F);
-	if (fpr[i.r1] != fpr[i.r2])
+	if (fpr[i.r1].f != fpr[i.r2].f)
+		JUMP(i.r0);
+
+	DISPATCH();
+
+	DO(BNER_D);
+	if (fpr[i.r1].d != fpr[i.r2].d)
 		JUMP(i.r0);
 
 	DISPATCH();
@@ -704,7 +789,13 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(BEQR_F);
-	if (fpr[i.r1] == fpr[i.r2])
+	if (fpr[i.r1].f == fpr[i.r2].f)
+		JUMP(i.r0);
+
+	DISPATCH();
+
+	DO(BEQR_D);
+	if (fpr[i.r1].d == fpr[i.r2].d)
 		JUMP(i.r0);
 
 	DISPATCH();
@@ -734,7 +825,13 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(BGTR_F);
-	if (fpr[i.r1] > fpr[i.r2])
+	if (fpr[i.r1].f > fpr[i.r2].f)
+		JUMP(i.r0);
+
+	DISPATCH();
+
+	DO(BGTR_D);
+	if (fpr[i.r1].d > fpr[i.r2].d)
 		JUMP(i.r0);
 
 	DISPATCH();
@@ -776,31 +873,25 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(BGER_F);
-	if (fpr[i.r1] >= fpr[i.r2])
+	if (fpr[i.r1].f >= fpr[i.r2].f)
 		JUMP(i.r0);
 
 	DISPATCH();
 
-	DO(BLEI);
-	if (gpr[i.r1] <= i.o)
+	DO(BGER_D);
+	if (fpr[i.r1].d >= fpr[i.r2].d)
 		JUMP(i.r0);
 
 	DISPATCH();
 
-	DO(BLEI_U);
-	if ((uint64_t)gpr[i.r1] <= (uint64_t)i.o)
+	DO(BLEI);
+	if (gpr[i.r1] <= i.o)
 		JUMP(i.r0);
 
 	DISPATCH();
 
-	DO(BLTGTR_F);
-	double f0 = fpr[i.r1];
-	double f1 = fpr[i.r2];
-
-	if (isnan(f0) || isnan(f1))
-		JUMP(++pc);
-
-	if (!(f0 >= f1) || !(f0 <= f1))
+	DO(BLEI_U);
+	if ((uint64_t)gpr[i.r1] <= (uint64_t)i.o)
 		JUMP(i.r0);
 
 	DISPATCH();
@@ -842,7 +933,11 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(RETVAL_F);
-	fpr[i.r0] = retval_f;
+	fpr[i.r0].f = retval_f;
+	DISPATCH();
+
+	DO(RETVAL_D);
+	fpr[i.r0].d = retval_f;
 	DISPATCH();
 
 	DO(PARAM);
@@ -851,9 +946,10 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 
 	DO(PARAM_F);
 	if (i.r1 == EJIT_FLOAT)
-		fpr[i.r2] = args[i.r0].f;
+		fpr[i.r2].f = args[i.r0].f;
 	else
-		fpr[i.r2] = args[i.r0].d;
+		fpr[i.r2].d = args[i.r0].d;
+
 	DISPATCH();
 
 	DO(ARG);
@@ -867,12 +963,22 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(ARG_F);
-	struct ejit_arg a = ejit_build_arg_f(i.r1, fpr[i.r2]);
+	struct ejit_arg a;
+	if (i.r1 == EJIT_DOUBLE)
+		a = ejit_build_arg_f(i.r1, fpr[i.r2].d);
+	else
+		a = ejit_build_arg_f(i.r1, fpr[i.r2].f);
+
 	vec_append(&state->args, &a);
 	DISPATCH();
 
 	DO(ARG_FI);
-	struct ejit_arg a = ejit_build_arg_f(i.r1, i.d);
+	struct ejit_arg a;
+	if (i.r1 == EJIT_DOUBLE)
+		a = ejit_build_arg_f(i.r1, i.d);
+	else
+		a = ejit_build_arg_f(i.r1, i.f);
+
 	vec_append(&state->args, &a);
 	DISPATCH();
 
@@ -885,7 +991,7 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	retval = ejit_run_interp(f, argc, args, state);
 
 	gpr = ((long *)state->gprs.buf) + prev_gprs;
-	fpr = ((double *)state->fprs.buf) + prev_fprs;
+	fpr = ((union fpr *)state->fprs.buf) + prev_fprs;
 	vec_shrink(&state->args, prev_argc);
 	DISPATCH();
 
@@ -927,11 +1033,21 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
 	DISPATCH();
 
 	DO(RETR_F);
-	retval_f = fpr[i.r0];
+	retval_f = fpr[i.r0].f;
+	goto out_float;
+	DISPATCH();
+
+	DO(RETR_D);
+	retval_f = fpr[i.r0].d;
 	goto out_float;
 	DISPATCH();
 
 	DO(RETI_F);
+	retval_f = i.f;
+	goto out_float;
+	DISPATCH();
+
+	DO(RETI_D);
 	retval_f = i.d;
 	goto out_float;
 	DISPATCH();
diff --git a/tests/absr_d.c b/tests/absr_d.c
new file mode 100644
index 0000000..20424a7
--- /dev/null
+++ b/tests/absr_d.c
@@ -0,0 +1,22 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[1] = {
+		EJIT_OPERAND_FPR(0, EJIT_DOUBLE)
+	};
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 1, operands);
+	ejit_absr_d(f, EJIT_FPR(0), EJIT_FPR(0));
+	ejit_retr_d(f, EJIT_FPR(0));
+	ejit_select_compile_func(f, 0, 1, false, do_jit);
+
+	assert(erff1(f, EJIT_ARG(0.0, double)) == 0.0);
+	assert(erff1(f, EJIT_ARG(-0.0, double)) == 0.0);
+	assert(erff1(f, EJIT_ARG(0.5, double)) == 0.5);
+	assert(erff1(f, EJIT_ARG(-0.5, double)) == 0.5);
+	ejit_destroy_func(f);
+}
diff --git a/tests/absr_f.c b/tests/absr_f.c
index d5411e5..876d82c 100644
--- a/tests/absr_f.c
+++ b/tests/absr_f.c
@@ -7,16 +7,16 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[1] = {
-		EJIT_OPERAND_FPR(0, EJIT_DOUBLE)
+		EJIT_OPERAND_FPR(0, EJIT_FLOAT)
 	};
-	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 1, operands);
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(float), 1, operands);
 	ejit_absr_f(f, EJIT_FPR(0), EJIT_FPR(0));
 	ejit_retr_f(f, EJIT_FPR(0));
 	ejit_select_compile_func(f, 0, 1, false, do_jit);
 
-	assert(ejit_run_func_f_1(f, EJIT_ARG(0.0, double)) == 0.0);
-	assert(ejit_run_func_f_1(f, EJIT_ARG(-0.0, double)) == 0.0);
-	assert(ejit_run_func_f_1(f, EJIT_ARG(0.5, double)) == 0.5);
-	assert(ejit_run_func_f_1(f, EJIT_ARG(-0.5, double)) == 0.5);
+	assert(ejit_run_func_f_1(f, EJIT_ARG(0.0, float)) == 0.0);
+	assert(ejit_run_func_f_1(f, EJIT_ARG(-0.0, float)) == 0.0);
+	assert(ejit_run_func_f_1(f, EJIT_ARG(0.5, float)) == 0.5);
+	assert(ejit_run_func_f_1(f, EJIT_ARG(-0.5, float)) == 0.5);
 	ejit_destroy_func(f);
 }
diff --git a/tests/addr_d.c b/tests/addr_d.c
new file mode 100644
index 0000000..db48ef6
--- /dev/null
+++ b/tests/addr_d.c
@@ -0,0 +1,24 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 2, operands);
+
+	ejit_addr_d(f, EJIT_FPR(0), EJIT_FPR(0), EJIT_FPR(1));
+	ejit_retr_d(f, EJIT_FPR(0));
+
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+
+	assert(erff2(f, EJIT_ARG(42., double), EJIT_ARG(69., double)) == 111.);
+	assert(erff2(f, EJIT_ARG(42.5, double), EJIT_ARG(69.5, double)) == 112.);
+	ejit_destroy_func(f);
+}
diff --git a/tests/addr_f.c b/tests/addr_f.c
index cfaa173..6eecbfb 100644
--- a/tests/addr_f.c
+++ b/tests/addr_f.c
@@ -7,20 +7,22 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
 
-	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 2, operands);
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(float), 2, operands);
 
 	ejit_addr_f(f, EJIT_FPR(0), EJIT_FPR(0), EJIT_FPR(1));
 	ejit_retr_f(f, EJIT_FPR(0));
 
-	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(float), do_jit);
+
+	assert(erff2(f, EJIT_ARG(42., float), EJIT_ARG(69., float)
+				) == 111.);
+
+	assert(erff2(f, EJIT_ARG(42.5, float), EJIT_ARG(69.5, float)
+				) == 112.);
 
-	assert(ejit_run_func_f_2(f, EJIT_ARG(42., double),
-	                         EJIT_ARG(69., double)) == 111.);
-	assert(ejit_run_func_f_2(f, EJIT_ARG(42.5, double),
-	                         EJIT_ARG(69.5, double)) == 112.);
 	ejit_destroy_func(f);
 }
diff --git a/tests/beqr_d.c b/tests/beqr_d.c
new file mode 100644
index 0000000..62e4269
--- /dev/null
+++ b/tests/beqr_d.c
@@ -0,0 +1,37 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
+
+	struct ejit_reloc r = ejit_beqr_d(f, EJIT_FPR(0), EJIT_FPR(1));
+	ejit_reti(f, 0);
+
+	struct ejit_label l = ejit_label(f);
+	ejit_patch(f, r, l);
+
+	ejit_reti(f, 1);
+
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(0, double)) == 1);
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(1, double)) == 0);
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(-1, double)) == 0);
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(1, double)) == 1);
+
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(0.0/0.0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0.0/0.0, double), EJIT_ARG(0, double)) == 0);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/beqr_f.c b/tests/beqr_f.c
index a8319ba..00bd84c 100644
--- a/tests/beqr_f.c
+++ b/tests/beqr_f.c
@@ -7,8 +7,8 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
 
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
@@ -21,25 +21,31 @@ int main(int argc, char *argv[])
 
 	ejit_reti(f, 1);
 
-	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
-
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(0, double)) == 1);
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(1, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(1, double),
-	                       EJIT_ARG(0, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(-1, double),
-	                       EJIT_ARG(0, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(-1, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(1, double),
-	                       EJIT_ARG(1, double)) == 1);
-
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(0.0/0.0, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(0.0/0.0, double),
-	                       EJIT_ARG(0, double)) == 0);
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(float), do_jit);
+
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(0, float)
+				) == 1);
+
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(1, float)
+				) == 0);
+
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(0, float)
+				) == 0);
+
+	assert(erf2(f, EJIT_ARG(-1, float), EJIT_ARG(0, float)
+				) == 0);
+
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(-1, float)
+				) == 0);
+
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(1, float)
+				) == 1);
+
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(0.0/0.0, float)
+				) == 0);
+
+	assert(erf2(f, EJIT_ARG(0.0/0.0, float), EJIT_ARG(0, float)
+				) == 0);
 
 	ejit_destroy_func(f);
 }
diff --git a/tests/bgtr_d.c b/tests/bgtr_d.c
new file mode 100644
index 0000000..57e8d0e
--- /dev/null
+++ b/tests/bgtr_d.c
@@ -0,0 +1,34 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
+	struct ejit_reloc r = ejit_bgtr_d(f, EJIT_FPR(0), EJIT_FPR(1));
+	ejit_reti(f, 0);
+
+	struct ejit_label l = ejit_label(f);
+	ejit_patch(f, r, l);
+	ejit_reti(f, 1);
+
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(long), do_jit);
+
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(1, double)) == 0);
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 1);
+	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(-1, double)) == 1);
+
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(0.0/0.0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0.0/0.0, double), EJIT_ARG(0, double)) == 0);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/bgtr_f.c b/tests/bgtr_f.c
index 2942cff..6fa9b45 100644
--- a/tests/bgtr_f.c
+++ b/tests/bgtr_f.c
@@ -7,8 +7,8 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
 
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
@@ -21,21 +21,26 @@ int main(int argc, char *argv[])
 
 	ejit_select_compile_func(f, 0, 2, EJIT_USE64(long), do_jit);
 
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(0, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(1, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(1, double),
-	                       EJIT_ARG(0, double)) == 1);
-	assert(ejit_run_func_2(f, EJIT_ARG(-1, double),
-	                       EJIT_ARG(0, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(-1, double)) == 1);
-
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(0.0/0.0, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(0.0/0.0, double),
-	                       EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(0, float)
+				) == 0);
+
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(1, float)
+				) == 0);
+
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(0, float)
+				) == 1);
+
+	assert(erf2(f, EJIT_ARG(-1, float), EJIT_ARG(0, float)
+				) == 0);
+
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(-1, float)
+				) == 1);
+
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(0.0/0.0, float)
+				) == 0);
+
+	assert(erf2(f, EJIT_ARG(0.0/0.0, float), EJIT_ARG(0, float)
+				) == 0);
 
 	ejit_destroy_func(f);
 }
diff --git a/tests/bler_d.c b/tests/bler_d.c
new file mode 100644
index 0000000..3d3d1d7
--- /dev/null
+++ b/tests/bler_d.c
@@ -0,0 +1,34 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
+	struct ejit_reloc r = ejit_bler_d(f, EJIT_FPR(0), EJIT_FPR(1));
+	ejit_reti(f, 0);
+
+	struct ejit_label l = ejit_label(f);
+	ejit_patch(f, r, l);
+	ejit_reti(f, 1);
+
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(long), do_jit);
+
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(0, double)) == 1);
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(1, double)) == 1);
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(0, double)) == 1);
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(-1, double)) == 0);
+
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(0.0/0.0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0.0/0.0, double), EJIT_ARG(0, double)) == 0);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/bler_f.c b/tests/bler_f.c
index 487900e..d49c13e 100644
--- a/tests/bler_f.c
+++ b/tests/bler_f.c
@@ -7,8 +7,8 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
 
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
@@ -21,21 +21,26 @@ int main(int argc, char *argv[])
 
 	ejit_select_compile_func(f, 0, 2, EJIT_USE64(long), do_jit);
 
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(0, double)) == 1);
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(1, double)) == 1);
-	assert(ejit_run_func_2(f, EJIT_ARG(1, double),
-	                       EJIT_ARG(0, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(-1, double),
-	                       EJIT_ARG(0, double)) == 1);
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(-1, double)) == 0);
-
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(0.0/0.0, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(0.0/0.0, double),
-	                       EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(0, float)
+				) == 1);
+
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(1, float)
+				) == 1);
+
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(0, float)
+				) == 0);
+
+	assert(erf2(f, EJIT_ARG(-1, float), EJIT_ARG(0, float)
+				) == 1);
+
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(-1, float)
+				) == 0);
+
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(0.0/0.0, float)
+				) == 0);
+
+	assert(erf2(f, EJIT_ARG(0.0/0.0, float), EJIT_ARG(0, float)
+				) == 0);
 
 	ejit_destroy_func(f);
 }
diff --git a/tests/bltr_d.c b/tests/bltr_d.c
new file mode 100644
index 0000000..7d251be
--- /dev/null
+++ b/tests/bltr_d.c
@@ -0,0 +1,34 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
+	struct ejit_reloc r = ejit_bltr_d(f, EJIT_FPR(0), EJIT_FPR(1));
+	ejit_reti(f, 0);
+
+	struct ejit_label l = ejit_label(f);
+	ejit_patch(f, r, l);
+	ejit_reti(f, 1);
+
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(long), do_jit);
+
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(1, double)) == 1);
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(0, double)) == 1);
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(-1, double)) == 0);
+
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(0.0/0.0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0.0/0.0, double), EJIT_ARG(0, double)) == 0);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/bltr_f.c b/tests/bltr_f.c
index 7cdd8fe..230a1bf 100644
--- a/tests/bltr_f.c
+++ b/tests/bltr_f.c
@@ -7,8 +7,8 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
 
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
@@ -21,21 +21,14 @@ int main(int argc, char *argv[])
 
 	ejit_select_compile_func(f, 0, 2, EJIT_USE64(long), do_jit);
 
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(0, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(1, double)) == 1);
-	assert(ejit_run_func_2(f, EJIT_ARG(1, double),
-	                       EJIT_ARG(0, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(-1, double),
-	                       EJIT_ARG(0, double)) == 1);
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(-1, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(0, float)) == 0);
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(1, float)) == 1);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(0, float)) == 0);
+	assert(erf2(f, EJIT_ARG(-1, float), EJIT_ARG(0, float)) == 1);
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(-1, float)) == 0);
 
-	assert(ejit_run_func_2(f, EJIT_ARG(0, double),
-	                       EJIT_ARG(0.0/0.0, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(0.0/0.0, double),
-	                       EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(0.0/0.0, float)) == 0);
+	assert(erf2(f, EJIT_ARG(0.0/0.0, float), EJIT_ARG(0, float)) == 0);
 
 	ejit_destroy_func(f);
 }
diff --git a/tests/bner_d.c b/tests/bner_d.c
new file mode 100644
index 0000000..b4a2e46
--- /dev/null
+++ b/tests/bner_d.c
@@ -0,0 +1,37 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
+	struct ejit_reloc r = ejit_bner_d(f, EJIT_FPR(0), EJIT_FPR(1));
+	ejit_reti(f, 0);
+
+	struct ejit_label l = ejit_label(f);
+	ejit_patch(f, r, l);
+
+	ejit_reti(f, 1);
+
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(1, double)) == 1);
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 1);
+	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(0, double)) == 1);
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(-1, double)) == 1);
+
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(1, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0, double), EJIT_ARG(0.0/0.0, double)) == 1);
+
+	assert(erf2(f, EJIT_ARG(0.0/0.0, double), EJIT_ARG(0, double)) == 1);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/bner_f.c b/tests/bner_f.c
index 3be835a..a48ef2c 100644
--- a/tests/bner_f.c
+++ b/tests/bner_f.c
@@ -7,8 +7,8 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
 
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
@@ -21,39 +21,16 @@ int main(int argc, char *argv[])
 
 	ejit_reti(f, 1);
 
-	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(float), do_jit);
 
-	assert(ejit_run_func_2(f,
-	                       EJIT_ARG(0, double),
-	                       EJIT_ARG(0, double)) == 0);
-
-	assert(ejit_run_func_2(f,
-	                       EJIT_ARG(0, double),
-	                       EJIT_ARG(1, double)) == 1);
-
-	assert(ejit_run_func_2(f,
-	                       EJIT_ARG(1, double),
-	                       EJIT_ARG(0, double)) == 1);
-
-	assert(ejit_run_func_2(f,
-	                       EJIT_ARG(-1, double),
-	                       EJIT_ARG(0, double)) == 1);
-
-	assert(ejit_run_func_2(f,
-	                       EJIT_ARG(0, double),
-	                       EJIT_ARG(-1, double)) == 1);
-
-	assert(ejit_run_func_2(f,
-	                       EJIT_ARG(1, double),
-	                       EJIT_ARG(1, double)) == 0);
-
-	assert(ejit_run_func_2(f,
-	                       EJIT_ARG(0, double),
-	                       EJIT_ARG(0.0/0.0, double)) == 1);
-
-	assert(ejit_run_func_2(f,
-	                       EJIT_ARG(0.0/0.0, double),
-	                       EJIT_ARG(0, double)) == 1);
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(0, float)) == 0);
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(1, float)) == 1);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(0, float)) == 1);
+	assert(erf2(f, EJIT_ARG(-1, float), EJIT_ARG(0, float)) == 1);
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(-1, float)) == 1);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(1, float)) == 0);
+	assert(erf2(f, EJIT_ARG(0, float), EJIT_ARG(0.0/0.0, float)) == 1);
+	assert(erf2(f, EJIT_ARG(0.0/0.0, float), EJIT_ARG(0, float)) == 1);
 
 	ejit_destroy_func(f);
 }
diff --git a/tests/divr_d.c b/tests/divr_d.c
new file mode 100644
index 0000000..83012fa
--- /dev/null
+++ b/tests/divr_d.c
@@ -0,0 +1,24 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 2, operands);
+
+	ejit_divr_d(f, EJIT_FPR(0), EJIT_FPR(0), EJIT_FPR(1));
+	ejit_retr_d(f, EJIT_FPR(0));
+
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+
+	assert(erff2(f, EJIT_ARG(-0.5f, double), EJIT_ARG(0.5f, double)) == -1.0f);
+	assert(erff2(f, EJIT_ARG(1.25f, double), EJIT_ARG(0.5f, double)) == 2.5f);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/divr_f.c b/tests/divr_f.c
index 5ea1028..008f6ce 100644
--- a/tests/divr_f.c
+++ b/tests/divr_f.c
@@ -7,23 +7,18 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
-	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 2, operands);
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(float), 2, operands);
 
 	ejit_divr_f(f, EJIT_FPR(0), EJIT_FPR(0), EJIT_FPR(1));
 	ejit_retr_f(f, EJIT_FPR(0));
 
-	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(float), do_jit);
 
-	assert(erff2(f,
-	             EJIT_ARG(-0.5f, double),
-	             EJIT_ARG(0.5f, double)) == -1.0f);
-
-	assert(erff2(f,
-	             EJIT_ARG(1.25f, double),
-	             EJIT_ARG(0.5f, double)) == 2.5f);
+	assert(erff2(f, EJIT_ARG(-0.5f, float), EJIT_ARG(0.5f, float)) == -1.0f);
+	assert(erff2(f, EJIT_ARG(1.25f, float), EJIT_ARG(0.5f, float)) == 2.5f);
 
 	ejit_destroy_func(f);
 }
diff --git a/tests/eqr_d.c b/tests/eqr_d.c
new file mode 100644
index 0000000..cfcf898
--- /dev/null
+++ b/tests/eqr_d.c
@@ -0,0 +1,26 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
+
+	ejit_eqr_d(f, EJIT_GPR(0), EJIT_FPR(0), EJIT_FPR(1));
+	ejit_retr(f, EJIT_GPR(0));
+
+	ejit_select_compile_func(f, 1, 2, EJIT_USE64(long), do_jit);
+
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(1, double)) == 1);
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(0.0/0.0, double), EJIT_ARG(0.0/0.0, double)) == 0);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/eqr_f.c b/tests/eqr_f.c
index 44ee409..572eeda 100644
--- a/tests/eqr_f.c
+++ b/tests/eqr_f.c
@@ -7,8 +7,8 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
 
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
@@ -18,17 +18,9 @@ int main(int argc, char *argv[])
 
 	ejit_select_compile_func(f, 1, 2, EJIT_USE64(long), do_jit);
 
-	assert(ejit_run_func_2(f,
-	                       EJIT_ARG(1, double),
-	                       EJIT_ARG(1, double)) == 1);
-
-	assert(ejit_run_func_2(f,
-	                       EJIT_ARG(1, double),
-	                       EJIT_ARG(0, double)) == 0);
-
-	assert(ejit_run_func_2(f,
-	                       EJIT_ARG(0.0/0.0, double),
-	                       EJIT_ARG(0.0/0.0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(1, float)) == 1);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(0, float)) == 0);
+	assert(erf2(f, EJIT_ARG(0.0/0.0, float), EJIT_ARG(0.0/0.0, float)) == 0);
 
 	ejit_destroy_func(f);
 }
diff --git a/tests/gtr_d.c b/tests/gtr_d.c
new file mode 100644
index 0000000..35de463
--- /dev/null
+++ b/tests/gtr_d.c
@@ -0,0 +1,25 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
+
+	ejit_gtr_d(f, EJIT_GPR(0), EJIT_FPR(0), EJIT_FPR(1));
+	ejit_retr(f, EJIT_GPR(0));
+
+	ejit_select_compile_func(f, 1, 2, EJIT_USE64(long), do_jit);
+
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(1, double)) == 0);
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 1);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/gtr_f.c b/tests/gtr_f.c
index db60d4d..e65ad35 100644
--- a/tests/gtr_f.c
+++ b/tests/gtr_f.c
@@ -7,8 +7,8 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
 
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
@@ -18,8 +18,8 @@ int main(int argc, char *argv[])
 
 	ejit_select_compile_func(f, 1, 2, EJIT_USE64(long), do_jit);
 
-	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(1, double)) == 0);
-	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 1);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(1, float)) == 0);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(0, float)) == 1);
 
 	ejit_destroy_func(f);
 }
diff --git a/tests/ldi_d.c b/tests/ldi_d.c
index 2aad277..15a48b4 100644
--- a/tests/ldi_d.c
+++ b/tests/ldi_d.c
@@ -10,7 +10,7 @@ int main(int argc, char *argv[])
 	bool do_jit = argc > 1;
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 0, NULL);
 	ejit_ldi_d(f, EJIT_FPR(0), &data);
-	ejit_retr_f(f, EJIT_FPR(0));
+	ejit_retr_d(f, EJIT_FPR(0));
 
 	ejit_select_compile_func(f, 1, 0, EJIT_USE64(double), do_jit);
 
diff --git a/tests/ldxi_d.c b/tests/ldxi_d.c
index 6b03073..98474d2 100644
--- a/tests/ldxi_d.c
+++ b/tests/ldxi_d.c
@@ -15,7 +15,7 @@ int main(int argc, char *argv[])
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 1, operands);
 
 	ejit_ldxi_d(f, EJIT_FPR(0), EJIT_GPR(0), (uintptr_t)data);
-	ejit_retr_f(f, EJIT_FPR(0));
+	ejit_retr_d(f, EJIT_FPR(0));
 
 	ejit_select_compile_func(f, 1, 1, EJIT_USE64(long), do_jit);
 
diff --git a/tests/ldxr_d.c b/tests/ldxr_d.c
index e1e56e4..a2ed0b8 100644
--- a/tests/ldxr_d.c
+++ b/tests/ldxr_d.c
@@ -15,7 +15,7 @@ int main(int argc, char *argv[])
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 2, operands);
 
 	ejit_ldxr_d(f, EJIT_FPR(0), EJIT_GPR(0), EJIT_GPR(1));
-	ejit_retr_f(f, EJIT_FPR(0));
+	ejit_retr_d(f, EJIT_FPR(0));
 
 	ejit_select_compile_func(f, 2, 1, false, do_jit);
 
diff --git a/tests/ler_d.c b/tests/ler_d.c
new file mode 100644
index 0000000..81dbda0
--- /dev/null
+++ b/tests/ler_d.c
@@ -0,0 +1,26 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
+
+	ejit_ler_d(f, EJIT_GPR(0), EJIT_FPR(0), EJIT_FPR(1));
+	ejit_retr(f, EJIT_GPR(0));
+
+	ejit_select_compile_func(f, 1, 2, EJIT_USE64(double), do_jit);
+
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(1, double)) == 1);
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(0, double)) == 1);
+	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(-1, double)) == 1);
+	ejit_destroy_func(f);
+}
diff --git a/tests/ler_f.c b/tests/ler_f.c
index 04765c8..82bd664 100644
--- a/tests/ler_f.c
+++ b/tests/ler_f.c
@@ -7,8 +7,8 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
 
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
@@ -16,11 +16,11 @@ int main(int argc, char *argv[])
 	ejit_ler_f(f, EJIT_GPR(0), EJIT_FPR(0), EJIT_FPR(1));
 	ejit_retr(f, EJIT_GPR(0));
 
-	ejit_select_compile_func(f, 1, 2, EJIT_USE64(double), do_jit);
+	ejit_select_compile_func(f, 1, 2, EJIT_USE64(float), do_jit);
 
-	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(1, double)) == 1);
-	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 0);
-	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(0, double)) == 1);
-	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(-1, double)) == 1);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(1, float)) == 1);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(0, float)) == 0);
+	assert(erf2(f, EJIT_ARG(-1, float), EJIT_ARG(0, float)) == 1);
+	assert(erf2(f, EJIT_ARG(-1, float), EJIT_ARG(-1, float)) == 1);
 	ejit_destroy_func(f);
 }
diff --git a/tests/ltr_d.c b/tests/ltr_d.c
new file mode 100644
index 0000000..600b820
--- /dev/null
+++ b/tests/ltr_d.c
@@ -0,0 +1,27 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
+
+	ejit_ltr_d(f, EJIT_GPR(0), EJIT_FPR(0), EJIT_FPR(1));
+	ejit_retr(f, EJIT_GPR(0));
+
+	ejit_select_compile_func(f, 1, 2, EJIT_USE64(long), do_jit);
+
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(1, double)) == 0);
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 0);
+	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(0, double)) == 1);
+	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(-1, double)) == 0);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/ltr_f.c b/tests/ltr_f.c
index 863463f..94dd657 100644
--- a/tests/ltr_f.c
+++ b/tests/ltr_f.c
@@ -7,8 +7,8 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
 
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
@@ -18,10 +18,10 @@ int main(int argc, char *argv[])
 
 	ejit_select_compile_func(f, 1, 2, EJIT_USE64(long), do_jit);
 
-	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(1, double)) == 0);
-	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 0);
-	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(0, double)) == 1);
-	assert(erf2(f, EJIT_ARG(-1, double), EJIT_ARG(-1, double)) == 0);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(1, float)) == 0);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(0, float)) == 0);
+	assert(erf2(f, EJIT_ARG(-1, float), EJIT_ARG(0, float)) == 1);
+	assert(erf2(f, EJIT_ARG(-1, float), EJIT_ARG(-1, float)) == 0);
 
 	ejit_destroy_func(f);
 }
diff --git a/tests/movi_d.c b/tests/movi_d.c
new file mode 100644
index 0000000..0b8e4f6
--- /dev/null
+++ b/tests/movi_d.c
@@ -0,0 +1,16 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 0, NULL);
+	ejit_movi_d(f, EJIT_FPR(0), 3.14159f);
+	ejit_retr_d(f, EJIT_FPR(0));
+	ejit_select_compile_func(f, 0, 1, EJIT_USE64(double), do_jit);
+
+	assert(ejit_run_func_f(f, 0, NULL) == 3.14159f);
+	ejit_destroy_func(f);
+}
diff --git a/tests/movi_f.c b/tests/movi_f.c
index f003c2d..fb986a0 100644
--- a/tests/movi_f.c
+++ b/tests/movi_f.c
@@ -6,10 +6,10 @@ int main(int argc, char *argv[])
 {
 	(void)argv;
 	bool do_jit = argc > 1;
-	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 0, NULL);
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(float), 0, NULL);
 	ejit_movi_f(f, EJIT_FPR(0), 3.14159f);
 	ejit_retr_f(f, EJIT_FPR(0));
-	ejit_select_compile_func(f, 0, 1, EJIT_USE64(double), do_jit);
+	ejit_select_compile_func(f, 0, 1, EJIT_USE64(float), do_jit);
 
 	assert(ejit_run_func_f(f, 0, NULL) == 3.14159f);
 	ejit_destroy_func(f);
diff --git a/tests/movr_d.c b/tests/movr_d.c
new file mode 100644
index 0000000..1911ccf
--- /dev/null
+++ b/tests/movr_d.c
@@ -0,0 +1,19 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[1] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double))
+	};
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 1, operands);
+	ejit_movr_d(f, EJIT_FPR(1), EJIT_FPR(0));
+	ejit_retr_d(f, EJIT_FPR(1));
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+
+	assert(ejit_run_func_f_1(f, EJIT_ARG(42., double)) == 42.);
+	ejit_destroy_func(f);
+}
diff --git a/tests/movr_f.c b/tests/movr_f.c
index 9c73ead..890ec9d 100644
--- a/tests/movr_f.c
+++ b/tests/movr_f.c
@@ -7,13 +7,13 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[1] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float))
 	};
-	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 1, operands);
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(float), 1, operands);
 	ejit_movr_f(f, EJIT_FPR(1), EJIT_FPR(0));
 	ejit_retr_f(f, EJIT_FPR(1));
-	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(float), do_jit);
 
-	assert(ejit_run_func_f_1(f, EJIT_ARG(42., double)) == 42.);
+	assert(ejit_run_func_f_1(f, EJIT_ARG(42., float)) == 42.);
 	ejit_destroy_func(f);
 }
diff --git a/tests/mulr_d.c b/tests/mulr_d.c
new file mode 100644
index 0000000..dbac71f
--- /dev/null
+++ b/tests/mulr_d.c
@@ -0,0 +1,24 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 2, operands);
+
+	ejit_mulr_d(f, EJIT_FPR(0), EJIT_FPR(0), EJIT_FPR(1));
+	ejit_retr_d(f, EJIT_FPR(0));
+
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+
+	assert(erff2(f, EJIT_ARG(-0.5f, double), EJIT_ARG(0.50f, double)) == -0.25f);
+	assert(erff2(f, EJIT_ARG(0.25f, double), EJIT_ARG(0.75f, double)) == 0.1875f);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/mulr_f.c b/tests/mulr_f.c
index ad59b6e..c65d3eb 100644
--- a/tests/mulr_f.c
+++ b/tests/mulr_f.c
@@ -7,20 +7,18 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
-	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 2, operands);
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(float), 2, operands);
 
 	ejit_mulr_f(f, EJIT_FPR(0), EJIT_FPR(0), EJIT_FPR(1));
 	ejit_retr_f(f, EJIT_FPR(0));
 
-	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(float), do_jit);
 
-	assert(erff2(f, EJIT_ARG(-0.5f, double),
-	             EJIT_ARG(0.50f, double)) == -0.25f);
-	assert(erff2(f, EJIT_ARG(0.25f, double),
-	             EJIT_ARG(0.75f, double)) == 0.1875f);
+	assert(erff2(f, EJIT_ARG(-0.5f, float), EJIT_ARG(0.50f, float)) == -0.25f);
+	assert(erff2(f, EJIT_ARG(0.25f, float), EJIT_ARG(0.75f, float)) == 0.1875f);
 
 	ejit_destroy_func(f);
 }
diff --git a/tests/negr_d.c b/tests/negr_d.c
new file mode 100644
index 0000000..b57dcea
--- /dev/null
+++ b/tests/negr_d.c
@@ -0,0 +1,25 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[1] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double))
+	};
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 1, operands);
+
+	ejit_negr_d(f, EJIT_FPR(0), EJIT_FPR(0));
+	ejit_retr_d(f, EJIT_FPR(0));
+
+	ejit_select_compile_func(f, 0, 1, EJIT_USE64(double), do_jit);
+
+	assert(erff1(f, EJIT_ARG(0.0f, double)) == -0.0f);
+	assert(erff1(f, EJIT_ARG(0.5f, double)) == -0.5f);
+	assert(erff1(f, EJIT_ARG(1.0f / 0.0f, double)) == -1.0f / 0.0f);
+	assert(erff1(f, EJIT_ARG(-1.25f, double)) == 1.25f);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/negr_f.c b/tests/negr_f.c
index 77b7474..392abc6 100644
--- a/tests/negr_f.c
+++ b/tests/negr_f.c
@@ -7,19 +7,19 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[1] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float))
 	};
-	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 1, operands);
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(float), 1, operands);
 
 	ejit_negr_f(f, EJIT_FPR(0), EJIT_FPR(0));
 	ejit_retr_f(f, EJIT_FPR(0));
 
-	ejit_select_compile_func(f, 0, 1, EJIT_USE64(double), do_jit);
+	ejit_select_compile_func(f, 0, 1, EJIT_USE64(float), do_jit);
 
-	assert(erff1(f, EJIT_ARG(0.0f, double)) == -0.0f);
-	assert(erff1(f, EJIT_ARG(0.5f, double)) == -0.5f);
-	assert(erff1(f, EJIT_ARG(1.0f / 0.0f, double)) == -1.0f / 0.0f);
-	assert(erff1(f, EJIT_ARG(-1.25f, double)) == 1.25f);
+	assert(erff1(f, EJIT_ARG(0.0f, float)) == -0.0f);
+	assert(erff1(f, EJIT_ARG(0.5f, float)) == -0.5f);
+	assert(erff1(f, EJIT_ARG(1.0f / 0.0f, float)) == -1.0f / 0.0f);
+	assert(erff1(f, EJIT_ARG(-1.25f, float)) == 1.25f);
 
 	ejit_destroy_func(f);
 }
diff --git a/tests/ner_d.c b/tests/ner_d.c
new file mode 100644
index 0000000..52a2f51
--- /dev/null
+++ b/tests/ner_d.c
@@ -0,0 +1,25 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
+
+	ejit_ner_d(f, EJIT_GPR(0), EJIT_FPR(0), EJIT_FPR(1));
+	ejit_retr(f, EJIT_GPR(0));
+
+	ejit_select_compile_func(f, 1, 2, EJIT_USE64(long), do_jit);
+
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(1, double)) == 0);
+	assert(erf2(f, EJIT_ARG(1, double), EJIT_ARG(0, double)) == 1);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/ner_f.c b/tests/ner_f.c
index 687e9ed..fb60120 100644
--- a/tests/ner_f.c
+++ b/tests/ner_f.c
@@ -7,8 +7,8 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
 
 	struct ejit_func *f = ejit_create_func(EJIT_TYPE(long), 2, operands);
@@ -18,10 +18,8 @@ int main(int argc, char *argv[])
 
 	ejit_select_compile_func(f, 1, 2, EJIT_USE64(long), do_jit);
 
-	assert(ejit_run_func_2(f, EJIT_ARG(1, double),
-	                       EJIT_ARG(1, double)) == 0);
-	assert(ejit_run_func_2(f, EJIT_ARG(1, double),
-	                       EJIT_ARG(0, double)) == 1);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(1, float)) == 0);
+	assert(erf2(f, EJIT_ARG(1, float), EJIT_ARG(0, float)) == 1);
 
 	ejit_destroy_func(f);
 }
diff --git a/tests/subr_d.c b/tests/subr_d.c
new file mode 100644
index 0000000..ef2c431
--- /dev/null
+++ b/tests/subr_d.c
@@ -0,0 +1,27 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+	};
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 2, operands);
+
+	ejit_subr_d(f, EJIT_FPR(0), EJIT_FPR(0), EJIT_FPR(1));
+	ejit_retr_d(f, EJIT_FPR(0));
+
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+
+	assert(erff2(f, EJIT_ARG(42., double), EJIT_ARG(69., double)
+	             ) == -27.);
+
+	assert(erff2(f, EJIT_ARG(42.5, double), EJIT_ARG(69., double)
+	             ) == -26.5);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/subr_f.c b/tests/subr_f.c
index 61c3916..a0f3059 100644
--- a/tests/subr_f.c
+++ b/tests/subr_f.c
@@ -7,20 +7,20 @@ int main(int argc, char *argv[])
 	(void)argv;
 	bool do_jit = argc > 1;
 	struct ejit_operand operands[2] = {
-		EJIT_OPERAND_FPR(0, EJIT_TYPE(double)),
-		EJIT_OPERAND_FPR(1, EJIT_TYPE(double))
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float)),
+		EJIT_OPERAND_FPR(1, EJIT_TYPE(float))
 	};
-	struct ejit_func *f = ejit_create_func(EJIT_TYPE(double), 2, operands);
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(float), 2, operands);
 
 	ejit_subr_f(f, EJIT_FPR(0), EJIT_FPR(0), EJIT_FPR(1));
 	ejit_retr_f(f, EJIT_FPR(0));
 
-	ejit_select_compile_func(f, 0, 2, EJIT_USE64(double), do_jit);
+	ejit_select_compile_func(f, 0, 2, EJIT_USE64(float), do_jit);
 
-	assert(erff2(f, EJIT_ARG(42., double), EJIT_ARG(69., double)
+	assert(erff2(f, EJIT_ARG(42., float), EJIT_ARG(69., float)
 	             ) == -27.);
 
-	assert(erff2(f, EJIT_ARG(42.5, double), EJIT_ARG(69., double)
+	assert(erff2(f, EJIT_ARG(42.5, float), EJIT_ARG(69., float)
 	             ) == -26.5);
 
 	ejit_destroy_func(f);
diff --git a/tests/truncr_f_32.c b/tests/truncr_f_32.c
new file mode 100644
index 0000000..1de700f
--- /dev/null
+++ b/tests/truncr_f_32.c
@@ -0,0 +1,29 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float))
+	};
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(int32_t), 1, operands);
+
+	ejit_truncr_f_32(f, EJIT_GPR(0), EJIT_FPR(0));
+	ejit_retr(f, EJIT_GPR(0));
+
+	ejit_select_compile_func(f, 1, 1, EJIT_TYPE(int32_t), do_jit);
+
+	assert(erf1(f, EJIT_ARG(0.0, float)) == 0);
+	assert(erf1(f, EJIT_ARG(-0.0, float)) == 0);
+	assert(erf1(f, EJIT_ARG(0.5, float)) == 0);
+	assert(erf1(f, EJIT_ARG(-0.5, float)) == 0);
+	assert(erf1(f, EJIT_ARG(1.5, float)) == 1);
+	assert(erf1(f, EJIT_ARG(-1.5, float)) == -1);
+	assert(erf1(f, EJIT_ARG(2.5, float)) == 2);
+	assert(erf1(f, EJIT_ARG(-2.5, float)) == -2);
+
+	ejit_destroy_func(f);
+}
diff --git a/tests/truncr_f_64.c b/tests/truncr_f_64.c
new file mode 100644
index 0000000..994bb16
--- /dev/null
+++ b/tests/truncr_f_64.c
@@ -0,0 +1,29 @@
+#include <ejit/ejit.h>
+#include <assert.h>
+#include "do_jit.h"
+
+int main(int argc, char *argv[])
+{
+	(void)argv;
+	bool do_jit = argc > 1;
+	struct ejit_operand operands[2] = {
+		EJIT_OPERAND_FPR(0, EJIT_TYPE(float))
+	};
+	struct ejit_func *f = ejit_create_func(EJIT_TYPE(int64_t), 1, operands);
+
+	ejit_truncr_f_64(f, EJIT_GPR(0), EJIT_FPR(0));
+	ejit_retr(f, EJIT_GPR(0));
+
+	ejit_select_compile_func(f, 1, 1, EJIT_TYPE(int64_t), do_jit);
+
+	assert(erf1(f, EJIT_ARG(0.0, float)) == 0);
+	assert(erf1(f, EJIT_ARG(-0.0, float)) == 0);
+	assert(erf1(f, EJIT_ARG(0.5, float)) == 0);
+	assert(erf1(f, EJIT_ARG(-0.5, float)) == 0);
+	assert(erf1(f, EJIT_ARG(1.5, float)) == 1);
+	assert(erf1(f, EJIT_ARG(-1.5, float)) == -1);
+	assert(erf1(f, EJIT_ARG(2.5, float)) == 2);
+	assert(erf1(f, EJIT_ARG(-2.5, float)) == -2);
+
+	ejit_destroy_func(f);
+}
-- 
cgit v1.2.3