[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Guile-commits] 31/86: Better loading of args to registers; add tests
From: |
Andy Wingo |
Subject: |
[Guile-commits] 31/86: Better loading of args to registers; add tests |
Date: |
Wed, 3 Apr 2019 11:38:54 -0400 (EDT) |
wingo pushed a commit to branch lightening
in repository guile.
commit df0a5d738f5a9f15acc31d2bd515f0e391bad006
Author: Andy Wingo <address@hidden>
Date: Mon Mar 25 15:08:05 2019 +0100
Better loading of args to registers; add tests
---
.gitignore | 3 +
jit.h | 12 +++-
jit/x86.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++----
tests/Makefile | 2 +-
tests/test-addr_d.c | 28 +++++++++
tests/test-addr_f.c | 28 +++++++++
tests/test-addx.c | 65 ++++++++++++++++++++
7 files changed, 291 insertions(+), 15 deletions(-)
diff --git a/.gitignore b/.gitignore
index dc7bc25..ffa28c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,6 @@
/lightning.info
/tests/test-addr
/tests/test-addi
+/tests/test-addr_d
+/tests/test-addr_f
+/tests/test-addx
diff --git a/jit.h b/jit.h
index f52263f..3b14591 100644
--- a/jit.h
+++ b/jit.h
@@ -127,7 +127,8 @@ typedef enum jit_arg_abi
JIT_ARG_ABI_INT64,
JIT_ARG_ABI_POINTER,
JIT_ARG_ABI_FLOAT,
- JIT_ARG_ABI_DOUBLE
+ JIT_ARG_ABI_DOUBLE,
+ JIT_ARG_ABI_INTMAX = CHOOSE_32_64(JIT_ARG_ABI_INT32, JIT_ARG_ABI_INT64)
} jit_arg_abi_t;
typedef struct jit_arg
@@ -142,6 +143,12 @@ typedef struct jit_arg
} loc;
} jit_arg_t;
+typedef union jit_anyreg
+{
+ jit_gpr_t gpr;
+ jit_fpr_t fpr;
+} jit_anyreg_t;
+
JIT_API jit_bool_t init_jit(void);
JIT_API jit_state_t *jit_new_state(void);
@@ -166,6 +173,9 @@ JIT_API void jit_callr(jit_state_t *, jit_gpr_t f,
const jit_arg_t args[]);
JIT_API void jit_receive(jit_state_t*, size_t argc,
const jit_arg_abi_t abi[], jit_arg_t args[]);
+JIT_API void jit_load_args(jit_state_t *_jit, size_t argc,
+ const jit_arg_abi_t abi[], jit_arg_t args[],
+ const jit_anyreg_t regs[]);
#define JIT_PROTO_0(stem, ret) \
ret jit_##stem (jit_state_t* _jit)
diff --git a/jit/x86.c b/jit/x86.c
index 1b61737..08bda79 100644
--- a/jit/x86.c
+++ b/jit/x86.c
@@ -363,6 +363,35 @@ jit_callr(jit_state_t *_jit, jit_gpr_t f,
callr(_jit, f);
}
+static jit_bool_t
+is_fpr_arg(jit_arg_abi_t arg)
+{
+ switch (arg)
+ {
+ case JIT_ARG_ABI_UINT8:
+ case JIT_ARG_ABI_INT8:
+ case JIT_ARG_ABI_UINT16:
+ case JIT_ARG_ABI_INT16:
+ case JIT_ARG_ABI_UINT32:
+ case JIT_ARG_ABI_INT32:
+ case JIT_ARG_ABI_UINT64:
+ case JIT_ARG_ABI_INT64:
+ case JIT_ARG_ABI_POINTER:
+ return 0;
+ case JIT_ARG_ABI_FLOAT:
+ case JIT_ARG_ABI_DOUBLE:
+ return 1;
+ default:
+ abort();
+ }
+}
+
+static jit_bool_t
+is_gpr_arg(jit_arg_abi_t arg)
+{
+ return !is_fpr_arg(arg);
+}
+
void
jit_receive(jit_state_t *_jit,
size_t argc, const jit_arg_abi_t abi[], jit_arg_t args[])
@@ -400,16 +429,7 @@ jit_receive(jit_state_t *_jit,
#endif
for (size_t i = 0; i < argc; i++) {
- switch (abi[i]) {
- case JIT_ARG_ABI_UINT8:
- case JIT_ARG_ABI_INT8:
- case JIT_ARG_ABI_UINT16:
- case JIT_ARG_ABI_INT16:
- case JIT_ARG_ABI_UINT32:
- case JIT_ARG_ABI_INT32:
- case JIT_ARG_ABI_UINT64:
- case JIT_ARG_ABI_INT64:
- case JIT_ARG_ABI_POINTER:
+ if (is_gpr_arg(abi[i])) {
if (gpr_arg_idx < gpr_arg_count) {
args[i].kind = JIT_ARG_LOC_GPR;
args[i].loc.gpr = gpr_args[gpr_arg_idx];
@@ -417,9 +437,8 @@ jit_receive(jit_state_t *_jit,
} else {
abort();
}
- break;
- case JIT_ARG_ABI_FLOAT:
- case JIT_ARG_ABI_DOUBLE:
+ } else {
+ ASSERT(is_fpr_arg(abi[i]));
if (fpr_arg_idx < fpr_arg_count) {
args[i].kind = JIT_ARG_LOC_FPR;
args[i].loc.fpr = fpr_args[fpr_arg_idx];
@@ -427,7 +446,130 @@ jit_receive(jit_state_t *_jit,
} else {
abort();
}
+ }
+ }
+}
+
+void
+jit_load_args(jit_state_t *_jit, size_t argc,
+ const jit_arg_abi_t abi[], jit_arg_t args[],
+ const jit_anyreg_t regs[])
+{
+ /* First shuffle the arguments in registers into position. */
+ for (size_t i = 0; i < argc; i++) {
+ const jit_arg_t arg = args[i];
+ const jit_anyreg_t reg = regs[i];
+ switch (arg.kind) {
+ case JIT_ARG_LOC_IMM:
+ abort();
+ case JIT_ARG_LOC_GPR:
+ {
+ if (arg.loc.gpr != reg.gpr)
+ /* Arg in a reg but it's not the right one. See if this reg
+ holds some other arg, and swap if so. */
+ for (size_t j=i+1; j<argc; j++)
+ if (args[j].kind == JIT_ARG_LOC_GPR && args[j].loc.gpr == reg.gpr)
+ {
+ xchgr(_jit, rn(arg.loc.gpr), rn(reg.gpr));
+ args[j].loc.gpr = arg.loc.gpr;
+ args[i].loc.gpr = reg.gpr;
+ break;
+ }
+ if (arg.loc.gpr != reg.gpr)
+ /* Arg in reg, but it's not the right one, and the desired reg
+ is free. */
+ {
+ movr(_jit, rn(reg.gpr), rn(arg.loc.gpr));
+ args[i].loc.gpr = reg.gpr;
+ }
+ }
+ case JIT_ARG_LOC_FPR:
+ {
+ if (arg.loc.fpr != reg.fpr)
+ /* Arg in a reg but it's not the right one. See if this reg
+ holds some other arg, and swap if so. */
+ for (size_t j=i+1; j<argc; j++)
+ if (args[j].kind == JIT_ARG_LOC_FPR && args[j].loc.fpr == reg.fpr)
+ {
+ jit_fpr_t tmp = get_temp_xpr(_jit);
+ movr_d (_jit, tmp, rn(arg.loc.fpr));
+ movr_d (_jit, rn(arg.loc.fpr), rn(reg.fpr));
+ movr_d (_jit, rn(reg.fpr), tmp);
+ unget_temp_xpr(_jit);
+ args[j].loc.fpr = arg.loc.fpr;
+ args[i].loc.fpr = reg.fpr;
+ break;
+ }
+ if (arg.loc.fpr != reg.fpr)
+ /* Arg in reg, but it's not the right one, and the desired reg
+ is free. */
+ {
+ movr_d(_jit, rn(reg.fpr), rn(arg.loc.fpr));
+ args[i].loc.fpr = reg.fpr;
+ }
+ }
+ case JIT_ARG_LOC_MEM:
+ /* Load spilled arguments once we're done with registers. */
break;
+ default:
+ abort();
+ }
+ }
+
+ /* Load spilled arguments from memory into registers. */
+ for (size_t i = 0; i < argc; i++) {
+ const jit_arg_t arg = args[i];
+ const jit_anyreg_t reg = regs[i];
+ switch (arg.kind) {
+ case JIT_ARG_LOC_IMM:
+ abort();
+ case JIT_ARG_LOC_GPR:
+ case JIT_ARG_LOC_FPR:
+ break;
+ case JIT_ARG_LOC_MEM:
+ {
+ jit_gpr_t base = arg.loc.mem.base;
+ ptrdiff_t offset = arg.loc.mem.offset;
+ switch (abi[i]) {
+ case JIT_ARG_ABI_UINT8:
+ jit_ldxi_uc(_jit, reg.gpr, base, offset);
+ break;
+ case JIT_ARG_ABI_INT8:
+ jit_ldxi_c(_jit, reg.gpr, base, offset);
+ break;
+ case JIT_ARG_ABI_UINT16:
+ jit_ldxi_us(_jit, reg.gpr, base, offset);
+ break;
+ case JIT_ARG_ABI_INT16:
+ jit_ldxi_s(_jit, reg.gpr, base, offset);
+ break;
+ case JIT_ARG_ABI_UINT32:
+ jit_ldxi_ui(_jit, reg.gpr, base, offset);
+ break;
+ case JIT_ARG_ABI_INT32:
+ jit_ldxi_i(_jit, reg.gpr, base, offset);
+ break;
+ case JIT_ARG_ABI_UINT64:
+ jit_ldxi_l(_jit, reg.gpr, base, offset);
+ break;
+ case JIT_ARG_ABI_INT64:
+ jit_ldxi_l(_jit, reg.gpr, base, offset);
+ break;
+ case JIT_ARG_ABI_POINTER:
+ jit_ldxi_l(_jit, reg.gpr, base, offset);
+ break;
+ case JIT_ARG_ABI_FLOAT:
+ jit_ldxi_f(_jit, reg.fpr, base, offset);
+ break;
+ case JIT_ARG_ABI_DOUBLE:
+ jit_ldxi_d(_jit, reg.fpr, base, offset);
+ break;
+ default:
+ abort();
+ }
+ }
+ default:
+ abort();
}
}
}
diff --git a/tests/Makefile b/tests/Makefile
index ead09bd..2dbad2f 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,4 +1,4 @@
-TESTS = addr addi
+TESTS=$(sort $(patsubst test-%.c,%,$(wildcard test-*.c)))
CC = gcc
CFLAGS = -Wall -O0 -g
diff --git a/tests/test-addr_d.c b/tests/test-addr_d.c
new file mode 100644
index 0000000..cae33cd
--- /dev/null
+++ b/tests/test-addr_d.c
@@ -0,0 +1,28 @@
+#include "test.h"
+
+static void
+run_test(jit_state_t *j, uint8_t *arena_base, size_t arena_size)
+{
+ jit_begin(j, arena_base, arena_size);
+
+ jit_arg_abi_t abi[] = { JIT_ARG_ABI_DOUBLE, JIT_ARG_ABI_DOUBLE };
+ jit_arg_t args[2];
+ jit_receive(j, 2, abi, args);
+ ASSERT(args[0].kind == JIT_ARG_LOC_FPR);
+ ASSERT(args[1].kind == JIT_ARG_LOC_FPR);
+ jit_addr_d(j, JIT_F0, args[0].loc.fpr, args[1].loc.fpr);
+ jit_retr_d(j, JIT_F0);
+
+ size_t size = 0;
+ void* ret = jit_end(j, &size);
+
+ double (*f)(double, double) = ret;
+ ASSERT(f(42., 69.) == 111.);
+ ASSERT(f(42.5, 69.5) == 112.);
+}
+
+int
+main (int argc, char *argv[])
+{
+ return main_helper(argc, argv, run_test);
+}
diff --git a/tests/test-addr_f.c b/tests/test-addr_f.c
new file mode 100644
index 0000000..c85394a
--- /dev/null
+++ b/tests/test-addr_f.c
@@ -0,0 +1,28 @@
+#include "test.h"
+
+static void
+run_test(jit_state_t *j, uint8_t *arena_base, size_t arena_size)
+{
+ jit_begin(j, arena_base, arena_size);
+
+ jit_arg_abi_t abi[] = { JIT_ARG_ABI_FLOAT, JIT_ARG_ABI_FLOAT };
+ jit_arg_t args[2];
+ jit_receive(j, 2, abi, args);
+ ASSERT(args[0].kind == JIT_ARG_LOC_FPR);
+ ASSERT(args[1].kind == JIT_ARG_LOC_FPR);
+ jit_addr_f(j, JIT_F0, args[0].loc.fpr, args[1].loc.fpr);
+ jit_retr_f(j, JIT_F0);
+
+ size_t size = 0;
+ void* ret = jit_end(j, &size);
+
+ float (*f)(float, float) = ret;
+ ASSERT(f(42.f, 69.f) == 111.f);
+ ASSERT(f(42.5f, 69.5f) == 112.f);
+}
+
+int
+main (int argc, char *argv[])
+{
+ return main_helper(argc, argv, run_test);
+}
diff --git a/tests/test-addx.c b/tests/test-addx.c
new file mode 100644
index 0000000..664c139
--- /dev/null
+++ b/tests/test-addx.c
@@ -0,0 +1,65 @@
+#include "test.h"
+
+static void
+run_test(jit_state_t *j, uint8_t *arena_base, size_t arena_size)
+{
+ jit_begin(j, arena_base, arena_size);
+
+ const jit_arg_abi_t abi[] = { JIT_ARG_ABI_INTMAX, JIT_ARG_ABI_INTMAX };
+ jit_arg_t args[2];
+ const jit_anyreg_t regs[] = { { .gpr=JIT_R0 }, { .gpr=JIT_R1 }};
+
+ jit_receive(j, 2, abi, args);
+ jit_load_args(j, 2, abi, args, regs);
+ jit_movi(j, JIT_R2, 0);
+ jit_addcr(j, JIT_R0, JIT_R0, JIT_R1);
+ jit_addxi(j, JIT_R2, JIT_R2, 0);
+ jit_retr(j, JIT_R2);
+
+ size_t size = 0;
+ void* ret = jit_end(j, &size);
+
+ intmax_t (*f)(intmax_t, intmax_t) = ret;
+
+ ASSERT(f(0, 0) == 0);
+
+#if __WORDSIZE == 32
+ /* carry */
+ ASSERT(f(0xffffffff, 0xffffffff) == 1);
+ /* overflow */
+ ASSERT(f(0x7fffffff, 1) == 0);
+ /* overflow */
+ ASSERT(f(0x7fffffff, 0x7fffffff) == 0);
+ /* carry */
+ ASSERT(f(0x7fffffff, 0x80000000) == 0);
+ /* carry+overflow */
+ ASSERT(f(0x80000000, 0x80000000) == 1);
+#else
+ /* nothing */
+ ASSERT(f(0xffffffff, 0xffffffff) == 0);
+ /* nothing */
+ ASSERT(f(0x7fffffff, 1) == 0);
+ /* nothing */
+ ASSERT(f(0x7fffffff, 0x7fffffff) == 0);
+ /* nothing */
+ ASSERT(f(0x7fffffff, 0x80000000) == 0);
+ /* nothing */
+ ASSERT(f(0x80000000, 0x80000000) == 0);
+ /* carry */
+ ASSERT(f(0xffffffffffffffff, 0xffffffffffffffff) == 1);
+ /* overflow */
+ ASSERT(f(0x7fffffffffffffff, 1) == 0);
+ /* overflow */
+ ASSERT(f(0x7fffffffffffffff, 0x7fffffffffffffff) == 0);
+ /* overflow */
+ ASSERT(f(0x7fffffffffffffff, 0x8000000000000000) == 0);
+ /* carry+overflow */
+ ASSERT(f(0x8000000000000000, 0x8000000000000000) == 1);
+#endif
+}
+
+int
+main (int argc, char *argv[])
+{
+ return main_helper(argc, argv, run_test);
+}
- [Guile-commits] 25/86: Remove needless PUBLIC/HIDDEN definitions, (continued)
- [Guile-commits] 25/86: Remove needless PUBLIC/HIDDEN definitions, Andy Wingo, 2019/04/03
- [Guile-commits] 19/86: Update call/receive machinery, Andy Wingo, 2019/04/03
- [Guile-commits] 10/86: Remove autotools, Andy Wingo, 2019/04/03
- [Guile-commits] 21/86: "extern"-related cleanup, and further implementation, Andy Wingo, 2019/04/03
- [Guile-commits] 27/86: Make _rvs array static-const, Andy Wingo, 2019/04/03
- [Guile-commits] 11/86: Rename include to jit.h, move all files to jit/, Andy Wingo, 2019/04/03
- [Guile-commits] 33/86: Flesh out README, Andy Wingo, 2019/04/03
- [Guile-commits] 36/86: Add more tests, Andy Wingo, 2019/04/03
- [Guile-commits] 18/86: Add endian.h, Andy Wingo, 2019/04/03
- [Guile-commits] 30/86: Add "addi" test, Andy Wingo, 2019/04/03
- [Guile-commits] 31/86: Better loading of args to registers; add tests,
Andy Wingo <=
- [Guile-commits] 26/86: Inline private.h into jit.c, Andy Wingo, 2019/04/03
- [Guile-commits] 32/86: Convert tests to jit_load_args, Andy Wingo, 2019/04/03
- [Guile-commits] 34/86: Add note about current status, Andy Wingo, 2019/04/03
- [Guile-commits] 14/86: Simplify file names, Andy Wingo, 2019/04/03
- [Guile-commits] 39/86: Add remr tests, Andy Wingo, 2019/04/03
- [Guile-commits] 37/86: Tests for some div operations, Andy Wingo, 2019/04/03
- [Guile-commits] 35/86: Add new tests, Andy Wingo, 2019/04/03
- [Guile-commits] 28/86: Beginnings of port of x86 to new design, Andy Wingo, 2019/04/03
- [Guile-commits] 44/86: Add mov_addr test, Andy Wingo, 2019/04/03
- [Guile-commits] 38/86: Add more div tests, Andy Wingo, 2019/04/03