summaryrefslogtreecommitdiff
path: root/libguile/vm-i-scheme.c
diff options
context:
space:
mode:
Diffstat (limited to 'libguile/vm-i-scheme.c')
-rw-r--r--libguile/vm-i-scheme.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/libguile/vm-i-scheme.c b/libguile/vm-i-scheme.c
index 3e80a0ef5..5557e19b8 100644
--- a/libguile/vm-i-scheme.c
+++ b/libguile/vm-i-scheme.c
@@ -210,6 +210,8 @@ VM_DEFINE_FUNCTION (149, ge, "ge?", 2)
*/
/* The maximum/minimum tagged integers. */
+#undef INUM_MAX
+#undef INUM_MIN
#define INUM_MAX (INTPTR_MAX - 1)
#define INUM_MIN (INTPTR_MIN + scm_tc2_int)
@@ -227,9 +229,68 @@ VM_DEFINE_FUNCTION (149, ge, "ge?", 2)
RETURN (SFUNC (x, y)); \
}
+/* Assembly tagged integer arithmetic routines. This code uses the
+ `asm goto' feature introduced in GCC 4.5. */
+
+#if defined __x86_64__ && SCM_GNUC_PREREQ (4, 5)
+
+/* The macros below check the CPU's overflow flag to improve fixnum
+ arithmetic. The %rcx register is explicitly clobbered because `asm
+ goto' can't have outputs, in which case the `r' constraint could be
+ used to let the register allocator choose a register.
+
+ TODO: Use `cold' label attribute in GCC 4.6.
+ http://gcc.gnu.org/ml/gcc-patches/2010-10/msg01777.html */
+
+# define ASM_ADD(x, y) \
+ { \
+ asm volatile goto ("mov %1, %%rcx; " \
+ "test %[tag], %%cl; je %l[slow_add]; " \
+ "test %[tag], %0; je %l[slow_add]; " \
+ "add %0, %%rcx; jo %l[slow_add]; " \
+ "sub %[tag], %%rcx; " \
+ "mov %%rcx, (%[vsp])\n" \
+ : /* no outputs */ \
+ : "r" (x), "r" (y), \
+ [vsp] "r" (sp), [tag] "i" (scm_tc2_int) \
+ : "rcx", "memory" \
+ : slow_add); \
+ NEXT; \
+ } \
+ slow_add: \
+ do { } while (0)
+
+# define ASM_SUB(x, y) \
+ { \
+ asm volatile goto ("mov %0, %%rcx; " \
+ "test %[tag], %%cl; je %l[slow_sub]; " \
+ "test %[tag], %1; je %l[slow_sub]; " \
+ "sub %1, %%rcx; jo %l[slow_sub]; " \
+ "add %[tag], %%rcx; " \
+ "mov %%rcx, (%[vsp])\n" \
+ : /* no outputs */ \
+ : "r" (x), "r" (y), \
+ [vsp] "r" (sp), [tag] "i" (scm_tc2_int) \
+ : "rcx", "memory" \
+ : slow_sub); \
+ NEXT; \
+ } \
+ slow_sub: \
+ do { } while (0)
+
+#endif
+
+
VM_DEFINE_FUNCTION (150, add, "add", 2)
{
+#ifndef ASM_ADD
FUNC2 (+, scm_sum);
+#else
+ ARGS2 (x, y);
+ ASM_ADD (x, y);
+ SYNC_REGISTER ();
+ RETURN (scm_sum (x, y));
+#endif
}
VM_DEFINE_FUNCTION (151, add1, "add1", 1)
@@ -256,7 +317,14 @@ VM_DEFINE_FUNCTION (151, add1, "add1", 1)
VM_DEFINE_FUNCTION (152, sub, "sub", 2)
{
+#ifndef ASM_SUB
FUNC2 (-, scm_difference);
+#else
+ ARGS2 (x, y);
+ ASM_SUB (x, y);
+ SYNC_REGISTER ();
+ RETURN (scm_difference (x, y));
+#endif
}
VM_DEFINE_FUNCTION (153, sub1, "sub1", 1)
@@ -281,6 +349,9 @@ VM_DEFINE_FUNCTION (153, sub1, "sub1", 1)
RETURN (scm_difference (x, SCM_I_MAKINUM (1)));
}
+# undef ASM_ADD
+# undef ASM_SUB
+
VM_DEFINE_FUNCTION (154, mul, "mul", 2)
{
ARGS2 (x, y);