diff -ruN libjit/include/jit/jit-arch-arm.h libjit-mikyt/include/jit/jit-arch-arm.h
--- libjit/include/jit/jit-arch-arm.h 1970-01-01 01:00:00.000000000 +0100
+++ libjit-mikyt/include/jit/jit-arch-arm.h 2009-02-04 17:49:45.000000000 +0100
@@ -0,0 +1,38 @@
+/*
+ * jit-arch-arm.h - Architecture-specific definitions.
+ *
+ * Copyright (C) 2006 Southern Storm Software, Pty Ltd.
+ *
+ * The libjit library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * The libjit library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the libjit library. If not, see
+ * .
+ */
+
+#ifndef _JIT_ARCH_ARM_H
+#define _JIT_ARCH_ARM_H
+
+/*
+ * If defined _JIT_ARCH_GET_CURRENT_FRAME() macro assigns the current frame
+ * pointer to the supplied argument that has to be a void pointer.
+ */
+#if defined(__GNUC__)
+#define _JIT_ARCH_GET_CURRENT_FRAME(f) \
+ do { \
+ register void *__f asm("fp"); \
+ f = __f; \
+ } while(0)
+#else
+#undef _JIT_ARCH_GET_CURRENT_FRAME
+#endif
+
+#endif /* _JIT_ARCH_ARM_H */
diff -ruN libjit/jit/Makefile.am libjit-mikyt/jit/Makefile.am
--- libjit/jit/Makefile.am 2008-05-29 23:03:30.000000000 +0200
+++ libjit-mikyt/jit/Makefile.am 2008-10-15 18:12:29.000000000 +0200
@@ -78,7 +78,7 @@
EXTRA_DIST = \
mklabel.sh \
jit-rules-alpha.ins \
- jit-rules-arm.sel \
+ jit-rules-arm.ins \
jit-rules-x86.ins \
jit-rules-x86-64.ins
@@ -100,11 +100,11 @@
$(top_builddir)/tools/gen-rules$(EXEEXT) $(srcdir)/jit-rules-x86.ins \
>jit-rules-x86.inc
-jit-rules-arm.lo: jit-rules-arm.slc
+jit-rules-arm.lo: jit-rules-arm.inc
-jit-rules-arm.slc: jit-rules-arm.sel $(top_builddir)/tools/gen-sel$(EXEEXT)
- $(top_builddir)/tools/gen-sel$(EXEEXT) $(srcdir)/jit-rules-arm.sel \
- >jit-rules-arm.slc
+jit-rules-arm.inc: jit-rules-arm.ins $(top_builddir)/tools/gen-rules$(EXEEXT)
+ $(top_builddir)/tools/gen-rules$(EXEEXT) $(srcdir)/jit-rules-arm.ins \
+ >jit-rules-arm.inc
jit-rules-alpha.lo: jit-rules-alpha.inc
@@ -121,6 +121,6 @@
CLEANFILES = \
jit-interp-labels.h \
jit-rules-alpha.inc \
- jit-rules-arm.slc \
+ jit-rules-arm.inc \
jit-rules-x86.inc \
jit-rules-x86-64.inc
diff -ruN libjit/jit/jit-apply-arm.c libjit-mikyt/jit/jit-apply-arm.c
--- libjit/jit/jit-apply-arm.c 2008-01-24 21:12:50.000000000 +0100
+++ libjit-mikyt/jit/jit-apply-arm.c 2009-01-17 16:30:23.000000000 +0100
@@ -97,4 +97,47 @@
return (void *)buf;
}
+/**
+ * Creates the indirector, that is the trampoline that permits the Just In Time
+ * compilation of a method the first time that it is executed and its direct execution
+ * the following times
+ */
+void *_jit_create_indirector(unsigned char *buf, void **entry)
+{
+ arm_inst_buf inst;
+ void *start = (void *)buf;
+
+ /* Initialize the instruction buffer */
+ arm_inst_buf_init(inst, buf, buf + jit_indirector_size);
+
+ //Load the content of memory at address "entry", that is, the entry point of the function
+ arm_mov_reg_imm(inst,ARM_WORK,entry);
+ arm_mov_reg_membase(inst,ARM_WORK,ARM_WORK,0,4);
+
+ /* Jump to the entry point. */
+ arm_mov_reg_reg(inst, ARM_PC, ARM_WORK);
+
+ /* Flush the cache lines that we just wrote */
+ jit_flush_exec(buf, ((unsigned char *)(inst.current)) - buf);
+
+ return start;
+}
+
+void _jit_pad_buffer(unsigned char *buf, int len)
+{
+ arm_inst_buf inst;
+
+ /* Initialize the instruction buffer */
+ arm_inst_buf_init(inst, buf, buf + len*4);
+ while(len > 0)
+ {
+ /* Traditional arm NOP */
+ arm_nop(inst);
+ --len;
+ }
+
+ /* Flush the cache lines that we just wrote */
+ jit_flush_exec(buf, ((unsigned char *)(inst.current)) - buf);
+}
+
#endif /* arm */
diff -ruN libjit/jit/jit-apply-arm.h libjit-mikyt/jit/jit-apply-arm.h
--- libjit/jit/jit-apply-arm.h 2008-01-24 21:12:50.000000000 +0100
+++ libjit-mikyt/jit/jit-apply-arm.h 2009-01-17 16:30:23.000000000 +0100
@@ -36,4 +36,37 @@
*/
#define jit_redirector_size 128
+/*
+ * The number of bytes that are needed for a indirector stub.
+ * This includes any extra bytes that are needed for alignment.
+ */
+#define jit_indirector_size 24
+
+/*
+* Defines the alignment for the stack pointer at a public interface.
+* As of the "Procedure Call Standard for the ARM Architecture" (AAPCS release 2.07)
+* SP mod 8 = 0
+* must always be true at every public interface (function calls, etc)
+*/
+#define JIT_SP_ALIGN_PUBLIC 8
+
+/* Redefine jit_builtin_apply in order to correctly align the stack pointer
+* to JIT_SP_ALING_PUBLIC bytes before calling __builtin_apply to execute the jit-compiled function
+*/
+#define jit_builtin_apply(func,args,size,return_float,return_buf) \
+do { \
+ register void *sp asm("sp"); \
+ while(((unsigned int)sp) % JIT_SP_ALIGN_PUBLIC != 0) \
+ { \
+ sp=(void *)(((unsigned int) sp)+1); \
+ } \
+ (return_buf) = __builtin_apply \
+ ((void (*)())(func), (args), (size)); \
+} while (0)
+
+/*
+ * We should pad unused code space with NOP's.
+ */
+#define jit_should_pad 1
+
#endif /* _JIT_APPLY_ARM_H */
diff -ruN libjit/jit/jit-apply-func.h libjit-mikyt/jit/jit-apply-func.h
--- libjit/jit/jit-apply-func.h 2008-05-26 23:06:29.000000000 +0200
+++ libjit-mikyt/jit/jit-apply-func.h 2008-12-20 19:09:52.000000000 +0100
@@ -48,32 +48,44 @@
(return_buf) = __builtin_apply \
((void (*)())(func), (args), (size)); \
} while (0)
+#endif
+#if !defined(jit_builtin_apply_args)
#define jit_builtin_apply_args(type,args) \
do { \
(args) = (type)__builtin_apply_args(); \
} while (0)
+#endif
+#if !defined(jit_builtin_return_int)
#define jit_builtin_return_int(return_buf) \
do { \
__builtin_return((return_buf)); \
} while (0)
+#endif
+#if !defined(jit_builtin_return_long)
#define jit_builtin_return_long(return_buf) \
do { \
__builtin_return((return_buf)); \
} while (0)
+#endif
+#if !defined(jit_builtin_return_float)
#define jit_builtin_return_float(return_buf) \
do { \
__builtin_return((return_buf)); \
} while (0)
+#endif
+#if !defined(jit_builtin_return_double)
#define jit_builtin_return_double(return_buf) \
do { \
__builtin_return((return_buf)); \
} while (0)
+#endif
+#if !defined(jit_builtin_return_nfloat)
#define jit_builtin_return_nfloat(return_buf) \
do { \
__builtin_return((return_buf)); \
diff -ruN libjit/jit/jit-cache.c libjit-mikyt/jit/jit-cache.c
--- libjit/jit/jit-cache.c 2008-03-03 15:49:06.000000000 +0100
+++ libjit-mikyt/jit/jit-cache.c 2009-02-05 13:04:29.000000000 +0100
@@ -27,6 +27,7 @@
#include "jit-internal.h"
#include "jit-cache.h"
#include "jit-apply-func.h"
+//#include
#ifdef __cplusplus
extern "C" {
diff -ruN libjit/jit/jit-dump.c libjit-mikyt/jit/jit-dump.c
--- libjit/jit/jit-dump.c 2008-12-22 19:49:47.000000000 +0100
+++ libjit-mikyt/jit/jit-dump.c 2008-01-25 08:27:00.000000000 +0100
@@ -846,14 +846,17 @@
while((block = jit_block_next(func, block)) != 0)
{
/* Output the block's label, if it has one */
- if(block->label != jit_label_undefined)
+ if(prev_block && block->label == jit_label_undefined)
{
- fprintf(stream, ".L%ld:\n", (long)(block->label));
+ /* A new block was started, but it doesn't have a label yet */
+ if(_jit_block_get_last(block) != 0)
+ {
+ block->label = (func->builder->next_label)++;
+ }
}
- else if (prev_block && _jit_block_get_last(block) != 0)
+ if(block->label != jit_label_undefined)
{
- /* A new block was started, but it doesn't have a label yet */
- fprintf(stream, ".L:\n");
+ fprintf(stream, ".L%ld:\n", (long)(block->label));
}
prev_block = 1;
diff -ruN libjit/jit/jit-function.c libjit-mikyt/jit/jit-function.c
--- libjit/jit/jit-function.c 2008-05-28 08:13:48.000000000 +0200
+++ libjit-mikyt/jit/jit-function.c 2009-02-05 13:06:07.000000000 +0100
@@ -26,6 +26,7 @@
#include "jit-reg-alloc.h"
#include "jit-apply-func.h"
#include "jit-setjmp.h"
+#include "jit-cache.h"
#ifdef _JIT_COMPILE_DEBUG
#include
#endif
@@ -1207,7 +1208,7 @@
func = (jit_function_t)_jit_cache_get_method(context->cache, pc, &cookie);
if(!func)
{
- return 0;
+ return 0;
}
/* Convert the cookie into a handler address */
@@ -1598,3 +1599,4 @@
return (func->builder->next_label)++;
}
+
diff -ruN libjit/jit/jit-gen-arm.h libjit-mikyt/jit/jit-gen-arm.h
--- libjit/jit/jit-gen-arm.h 2008-01-24 21:12:52.000000000 +0100
+++ libjit-mikyt/jit/jit-gen-arm.h 2009-02-04 17:49:45.000000000 +0100
@@ -1,7 +1,8 @@
/*
- * arm_codegen.h - Code generation macros for the ARM processor.
+ * jit-gen-arm.h - Code generation macros for the ARM processor.
*
* Copyright (C) 2003, 2004 Southern Storm Software, Pty Ltd.
+ * Copyright (C) 2008 Michele Tartara
*
* This file is part of the libjit library.
*
@@ -22,7 +23,7 @@
#ifndef _ARM_CODEGEN_H
#define _ARM_CODEGEN_H
-
+#include
#ifdef __cplusplus
extern "C" {
#endif
@@ -61,15 +62,30 @@
*/
typedef enum
{
- ARM_F0 = 0,
- ARM_F1 = 1,
- ARM_F2 = 2,
- ARM_F3 = 3,
- ARM_F4 = 4,
- ARM_F5 = 5,
- ARM_F6 = 6,
- ARM_F7 = 7
-
+ ARM_S0 = 0,
+ ARM_S1 = 1,
+ ARM_S2 = 2,
+ ARM_S3 = 3,
+ ARM_S4 = 4,
+ ARM_S5 = 5,
+ ARM_S6 = 6,
+ ARM_S7 = 7,
+ ARM_S8 = 8,
+ ARM_S9 = 9,
+ ARM_S10 = 10,
+ ARM_S11 = 11,
+ ARM_S12 = 12,
+ ARM_S13 = 13,
+ ARM_S14 = 14,
+ ARM_S15 = 15,
+ ARM_D8 = 8,
+ ARM_D9 = 9,
+ ARM_D10 = 10,
+ ARM_D11 = 11,
+ ARM_D12 = 12,
+ ARM_D13 = 13,
+ ARM_D14 = 14,
+ ARM_D15 = 15
} ARM_FREG;
/*
@@ -141,21 +157,9 @@
*/
typedef enum
{
- ARM_MVF = 0, /* Move */
- ARM_MNF = 1, /* Move negative */
- ARM_ABS = 2, /* Absolute value */
- ARM_RND = 3, /* Round */
- ARM_SQT = 4, /* Square root */
- ARM_LOG = 5, /* log10 */
- ARM_LGN = 6, /* ln */
- ARM_EXP = 7, /* exp */
- ARM_SIN = 8, /* sin */
- ARM_COS = 9, /* cos */
- ARM_TAN = 10, /* tan */
- ARM_ASN = 11, /* asin */
- ARM_ACS = 12, /* acos */
- ARM_ATN = 13 /* atan */
-
+ ARM_MVF = 0, /* Move - FCPY */
+ ARM_MNF = 1, /* Move negative - FNEG */
+ ARM_ABS = 2 /* Absolute value - FABS */
} ARM_FUNARY;
/*
@@ -163,20 +167,10 @@
*/
typedef enum
{
- ARM_ADF = 0, /* Add */
- ARM_MUF = 1, /* Multiply */
- ARM_SUF = 2, /* Subtract */
- ARM_RSF = 3, /* Reverse subtract */
- ARM_DVF = 4, /* Divide */
- ARM_RDF = 5, /* Reverse divide */
- ARM_POW = 6, /* pow */
- ARM_RPW = 7, /* Reverse pow */
- ARM_RMF = 8, /* Remainder */
- ARM_FML = 9, /* Fast multiply (32-bit only) */
- ARM_FDV = 10, /* Fast divide (32-bit only) */
- ARM_FRD = 11, /* Fast reverse divide (32-bit only) */
- ARM_POL = 12 /* Polar angle */
-
+ ARM_FADD = 0, /* Add */
+ ARM_FMUL = 1, /* Multiply */
+ ARM_FSUB = 2, /* Subtract */
+ ARM_FDIV = 4 /* Divide */
} ARM_FBINARY;
/*
@@ -265,6 +259,7 @@
(((unsigned int)(sreg)) << 16) | \
((unsigned int)((imm) & 0xFF))); \
} while (0)
+
#define arm_alu_reg_imm8_cond(inst,opc,dreg,sreg,imm,cond) \
do { \
arm_inst_add((inst), arm_build_prefix((cond), (1 << 25)) | \
@@ -382,6 +377,14 @@
} \
} while (0)
+#define arm_test_reg_membase(inst,opc,reg,basereg,disp,scratchreg) \
+ do { \
+ assert(reg!=scratchreg); \
+ assert(basereg!=scratchreg); \
+ arm_load_membase((inst), (tmpreg),(basereg),(disp)); \
+ arm_test_reg_reg((inst), (opc), (reg), (tmpreg)); \
+} while (0)
+
/*
* Move a value between registers.
*/
@@ -389,6 +392,17 @@
do { \
arm_alu_reg((inst), ARM_MOV, (dreg), (sreg)); \
} while (0)
+
+/**
+ * Move a value between floating point registers.
+ * @var inst is the pointer to the location of memory at which the instruction will be put
+ * @var dreg is the destination register
+ * @var freg is the source register
+ */
+#define arm_mov_freg_freg(inst,dreg,sreg) \
+ do { \
+ arm_alu_freg((inst), ARM_MVF, (dreg), (sreg)); \
+ } while (0)
/*
* Move an immediate value into a register. This is hard because
@@ -407,6 +421,14 @@
extern void _arm_mov_reg_imm
(arm_inst_buf *inst, int reg, int value, int execute_prefix);
extern int arm_is_complex_imm(int value);
+
+/**
+ * Moves the immediate value imm into register reg.
+ *
+ * In case imm is > 255, it builds the value one byte at a time, by calling _arm_mov_reg_imm
+ * This is done by using a big number of instruction.
+ * In that case, using mov_reg_imm (defined in jit-rules-arm.c is probably a better idea, when possible
+ */
#define arm_mov_reg_imm(inst,reg,imm) \
do { \
int __imm = (int)(imm); \
@@ -431,6 +453,136 @@
} \
} while (0)
+#define ARM_NOBASEREG (-1)
+
+/**
+ * LDR (Load Register), LDRB (Load Register Byte)
+ * Load the content of the memory area of size "size" at position basereg+disp+(indexreg<> 1; \
+ unsigned int dreg_bottom_bit = (dreg & 0x01); \
+ unsigned int sreg1_top_4_bits = (sreg1 & 0x1E) >> 1; \
+ unsigned int sreg1_bottom_bit = (sreg1 & 0x01); \
+ unsigned int sreg2_top_4_bits = (sreg2 & 0x1E) >> 1; \
+ unsigned int sreg2_bottom_bit = (sreg2 & 0x01); \
+ arm_inst_add((inst), arm_prefix(mask) | \
+ (((unsigned int)(dreg_top_4_bits)) << 12) | \
+ (((unsigned int)(dreg_bottom_bit)) << 22) | \
+ (((unsigned int)(sreg1_top_4_bits)) << 16) | \
+ (((unsigned int)(sreg1_bottom_bit)) << 7) | \
+ (((unsigned int)(sreg2_bottom_bit)) << 5) | \
+ ((unsigned int)(sreg2_top_4_bits))); \
+} while (0)
+
+/**
+* Perform a unary operation on a double-precision floating-point argument.
+* OPC is the number indicating the operation to execute (taken from enum ARM_FUNARY)
+* sreg is the register containing the operand
+* dreg is the destination register
+*/
#define arm_alu_freg(inst,opc,dreg,sreg) \
do { \
- arm_inst_add((inst), arm_prefix(0x0E008180) | \
- (((unsigned int)(opc)) << 20) | \
- (((unsigned int)(dreg)) << 12) | \
+ unsigned int mask; \
+ switch(opc) \
+ { \
+ case ARM_MVF: \
+ mask=0xEB00B40; \
+ break; \
+ case ARM_MNF: \
+ mask=0xEB10B40; \
+ break; \
+ case ARM_ABS: \
+ mask=0xEB00BC0; \
+ break; \
+ default: \
+ printf("Unimplemented unary operation %d in %s\n", opc, __FILE__); \
+ abort(); \
+ } \
+ arm_inst_add((inst), arm_prefix(mask) | \
+ (((unsigned int)(dreg)) << 12) | \
((unsigned int)(sreg))); \
} while (0)
+
+/**
+ * Perform a unary operation on a single-precision floating-point argument.
+ * OPC is the number indicating the operation to execute (taken from enum ARM_FUNARY)
+ * sreg is the register containing the operand
+ * dreg is the destination register
+ */
#define arm_alu_freg_32(inst,opc,dreg,sreg) \
do { \
- arm_inst_add((inst), arm_prefix(0x0E008100) | \
- (((unsigned int)(opc)) << 20) | \
- (((unsigned int)(dreg)) << 12) | \
- ((unsigned int)(sreg))); \
+ unsigned int mask; \
+ switch(opc) \
+ { \
+ case ARM_MVF: \
+ mask=0xEB00A40; \
+ break; \
+ case ARM_MNF: \
+ mask=0xEB10A40; \
+ break; \
+ case ARM_ABS: \
+ mask=0xEB00AC0; \
+ break; \
+ default: \
+ printf("Unimplemented OPCODE in %s\n", __FILE__); \
+ abort(); \
+ } \
+ unsigned int dreg_top_4_bits = (dreg & 0x1E) >> 1; \
+ unsigned int dreg_bottom_bit = (dreg & 0x01); \
+ unsigned int sreg_top_4_bits = (sreg & 0x1E) >> 1; \
+ unsigned int sreg_bottom_bit = (sreg & 0x01); \
+ arm_inst_add((inst), arm_prefix(mask) | \
+ (((unsigned int)(dreg_top_4_bits)) << 12) | \
+ (((unsigned int)(dreg_bottom_bit)) << 22) | \
+ (((unsigned int)(sreg_bottom_bit)) << 5) | \
+ ((unsigned int)(sreg_top_4_bits))); \
} while (0)
/*
@@ -598,6 +850,7 @@
/*
* Call a subroutine at a specific target location.
+ * (Equivalent to x86_call_code)
*/
#define arm_call(inst,target) \
do { \
@@ -645,6 +898,15 @@
} while (0)
/*
+ * Pop the top of the system stack and put it at a given offset from the position specified by basereg (that is, usually, the frame pointer). NB: This macro thrashes the content of ARM_WORK
+ */
+#define arm_pop_membase(inst,basereg,offset) \
+ do { \
+ arm_pop_reg((inst), ARM_WORK); \
+ arm_store_membase((inst),ARM_WORK,basereg,offset); \
+ } while (0)
+
+/*
* Set up a local variable frame, and save the registers in "regset".
*/
#define arm_setup_frame(inst,regset) \
@@ -710,6 +972,7 @@
} \
else \
{ \
+ assert(basereg!=ARM_WORK); \
arm_mov_reg_imm((inst), ARM_WORK, __mb_offset); \
arm_inst_add((inst), arm_prefix(0x07900000 | (mask)) | \
(((unsigned int)(basereg)) << 16) | \
@@ -721,6 +984,37 @@
do { \
arm_load_membase_either((inst), (reg), (basereg), (imm), 0); \
} while (0)
+
+/**
+ * Moves the content of 1 byte (is_half==0) or 2 bytes (is_half==1) from memory address basereg+disp+(indexreg<> 1; \
+ unsigned int reg_bottom_bit = (reg & 0x01); \
+ int __mb_offset = (int)(imm); \
+ if(__mb_offset >= 0 && __mb_offset < (1 << 10) && \
+ (__mb_offset & 3) == 0) \
+ { \
+ arm_inst_add((inst), arm_prefix(0x0D900A00 | (mask)) | \
+ (((unsigned int)(basereg)) << 16) | \
+ (((unsigned int)(reg_top_4_bits)) << 12) | \
+ (((unsigned int)(reg_bottom_bit)) << 22) | \
+ ((unsigned int)((__mb_offset / 4) & 0xFF))); \
+ } \
+ else if(__mb_offset > -(1 << 10) && __mb_offset < 0 && \
+ (__mb_offset & 3) == 0) \
+ { \
+ arm_inst_add((inst), arm_prefix(0x0D100A00 | (mask)) | \
+ (((unsigned int)(basereg)) << 16) | \
+ (((unsigned int)(reg_top_4_bits)) << 12) | \
+ (((unsigned int)(reg_bottom_bit)) << 22) | \
+ ((unsigned int)(((-__mb_offset) / 4) & 0xFF)));\
+ } \
+ else \
+ { \
+ assert(reg != ARM_WORK); \
+ assert(basereg!=ARM_WORK); \
+ if(__mb_offset > 0) \
+ { \
+ arm_mov_reg_imm((inst), ARM_WORK, __mb_offset); \
+ arm_alu_reg_reg((inst), ARM_ADD, ARM_WORK, (basereg), ARM_WORK); \
+ } \
+ else \
+ { \
+ arm_mov_reg_imm((inst), ARM_WORK, -__mb_offset); \
+ arm_alu_reg_reg((inst), ARM_SUB, ARM_WORK, (basereg), ARM_WORK); \
+ } \
+ arm_inst_add((inst), arm_prefix(0x0D900A00 | (mask)) | \
+ (((unsigned int)ARM_WORK) << 16) | \
+ (((unsigned int)(reg_top_4_bits)) << 12) | \
+ (((unsigned int)(reg_bottom_bit)) << 22)); \
+ } \
+} while (0)
+
+/**
+ * FLDD
+ */
+#define arm_load_membase_float64(inst,reg,basereg,imm) \
do { \
int __mb_offset = (int)(imm); \
if(__mb_offset >= 0 && __mb_offset < (1 << 10) && \
(__mb_offset & 3) == 0) \
{ \
- arm_inst_add((inst), arm_prefix(0x0D900100 | (mask)) | \
+ arm_inst_add((inst), arm_prefix(0x0D900B00) | \
(((unsigned int)(basereg)) << 16) | \
(((unsigned int)(reg)) << 12) | \
((unsigned int)((__mb_offset / 4) & 0xFF))); \
@@ -766,35 +1110,137 @@
else if(__mb_offset > -(1 << 10) && __mb_offset < 0 && \
(__mb_offset & 3) == 0) \
{ \
- arm_inst_add((inst), arm_prefix(0x0D180100 | (mask)) | \
+ arm_inst_add((inst), arm_prefix(0x0D100B00) | \
(((unsigned int)(basereg)) << 16) | \
(((unsigned int)(reg)) << 12) | \
((unsigned int)(((-__mb_offset) / 4) & 0xFF)));\
} \
else \
{ \
- arm_mov_reg_imm((inst), ARM_WORK, __mb_offset); \
- arm_alu_reg_reg((inst), ARM_ADD, ARM_WORK, \
- (basereg), ARM_WORK); \
- arm_inst_add((inst), arm_prefix(0x0D900100 | (mask)) | \
+ assert(reg != ARM_WORK); \
+ assert(basereg!=ARM_WORK); \
+ if(__mb_offset > 0) \
+ { \
+ arm_mov_reg_imm((inst), ARM_WORK, __mb_offset); \
+ arm_alu_reg_reg((inst), ARM_ADD, ARM_WORK, (basereg), ARM_WORK); \
+ } \
+ else \
+ { \
+ arm_mov_reg_imm((inst), ARM_WORK, -__mb_offset); \
+ arm_alu_reg_reg((inst), ARM_SUB, ARM_WORK, (basereg), ARM_WORK); \
+ } \
+ arm_inst_add((inst), arm_prefix(0x0D900B00) | \
(((unsigned int)ARM_WORK) << 16) | \
(((unsigned int)(reg)) << 12)); \
} \
} while (0)
+
#define arm_load_membase_float32(inst,reg,basereg,imm) \
do { \
arm_load_membase_float((inst), (reg), (basereg), (imm), 0); \
} while (0)
-#define arm_load_membase_float64(inst,reg,basereg,imm) \
- do { \
- arm_load_membase_float((inst), (reg), (basereg), \
- (imm), 0x00008000); \
- } while (0)
-/*
- * Store a value from a register into an address.
+/**
+* Load the content of the memory area at position basereg+disp into the float register "dfreg",
+* using the appropriate instruction depending whether the value to be loaded is_double (1 => 64 bits) or not (0 => 32 bits)
+* (it's similar to x86_fld_membase)
+*/
+#define arm_fld_membase(inst,dfreg,basereg,disp,is_double) \
+do { \
+ if (is_double) \
+ { \
+ arm_load_membase_float64((inst), (dfreg), (basereg), (disp)); \
+ } \
+ else \
+ { \
+ arm_load_membase_float32((inst), (dfreg), (basereg), (disp)); \
+ }\
+} while(0)
+
+/**
+ * Load the content of the memory area at position basereg+disp+(indexreg< 64 bits) or not (0 => 32 bits)
+ * (it's similar to x86_fld_memindex)
+ */
+#define arm_fld_memindex(inst,dfreg,basereg,disp,indexreg,shift,is_double,scratchreg) \
+ do { \
+ if (is_double) \
+ { \
+ arm_load_memindex_float64((inst), (dfreg), (basereg), (disp), (indexreg), (shift), (scratchreg)); \
+ } \
+ else \
+ { \
+ arm_load_memindex_float32((inst), (dfreg), (basereg), (disp), (indexreg), (shift), (scratchreg)); \
+ }\
+ } while(0)
+/**
+ * Load the content of the 64-bits memory area at position basereg+disp+(indexreg< 64 bits) or not (0 => 32 bits)
+ * (it's similar to x86_fst_memindex)
+ */
+#define arm_fst_memindex(inst,sfreg,basereg,disp,indexreg,shift,is_double,scratchreg) \
+do { \
+ if (is_double) \
+ { \
+ arm_store_memindex_float64((inst), (sfreg), (basereg), (disp), (indexreg), (shift), (scratchreg)); \
+ } \
+ else \
+ { \
+ arm_store_memindex_float32((inst), (sfreg), (basereg), (disp), (indexreg), (shift), (scratchreg)); \
+ }\
+} while(0)
+
+/**
+ * Store the content of the double float register "dfreg" into the 64-bits memory area at position basereg+disp+(indexreg<= 0 && __mb_offset < (1 << 10) && \
- (__mb_offset & 3) == 0) \
- { \
- arm_inst_add((inst), arm_prefix(0x0D800100 | (mask)) | \
- (((unsigned int)(basereg)) << 16) | \
- (((unsigned int)(reg)) << 12) | \
- ((unsigned int)((__mb_offset / 4) & 0xFF))); \
- } \
- else if(__mb_offset > -(1 << 10) && __mb_offset < 0 && \
- (__mb_offset & 3) == 0) \
- { \
- arm_inst_add((inst), arm_prefix(0x0D080100 | (mask)) | \
- (((unsigned int)(basereg)) << 16) | \
- (((unsigned int)(reg)) << 12) | \
- ((unsigned int)(((-__mb_offset) / 4) & 0xFF)));\
- } \
- else \
- { \
- arm_mov_reg_imm((inst), ARM_WORK, __mb_offset); \
- arm_alu_reg_reg((inst), ARM_ADD, ARM_WORK, \
- (basereg), ARM_WORK); \
- arm_inst_add((inst), arm_prefix(0x0D800100 | (mask)) | \
- (((unsigned int)ARM_WORK) << 16) | \
- (((unsigned int)(reg)) << 12)); \
- } \
- } while (0)
-#define arm_store_membase_float32(inst,reg,basereg,imm) \
- do { \
- arm_store_membase_float((inst), (reg), (basereg), (imm), 0); \
- } while (0)
+#define arm_store_membase_float32(inst,reg,basereg,imm) \
+do { \
+ unsigned int reg_top_4_bits = (reg & 0x1E) >> 1; \
+ unsigned int reg_bottom_bit = (reg & 0x01); \
+ int __mb_offset = (int)(imm); \
+ if(__mb_offset >= 0 && __mb_offset < (1 << 10) && (__mb_offset & 3) == 0) \
+ { \
+ arm_inst_add((inst), arm_prefix(0x0D800A00) | \
+ (((unsigned int)(basereg)) << 16) | \
+ (((unsigned int)(reg_top_4_bits)) << 12) | \
+ (((unsigned int)(reg_bottom_bit)) << 22) | \
+ ((unsigned int)((__mb_offset / 4) & 0xFF))); \
+ } \
+ else if(__mb_offset > -(1 << 10) && __mb_offset < 0 && (__mb_offset & 3) == 0) \
+ { \
+ arm_inst_add((inst), arm_prefix(0x0D000A00) | \
+ (((unsigned int)(basereg)) << 16) | \
+ (((unsigned int)(reg_top_4_bits)) << 12) | \
+ (((unsigned int)(reg_bottom_bit)) << 22) | \
+ ((unsigned int)(((-__mb_offset) / 4) & 0xFF))); \
+ } \
+ else \
+ { \
+ assert(reg != ARM_WORK); \
+ assert(basereg!=ARM_WORK); \
+ if(__mb_offset > 0) \
+ { \
+ arm_mov_reg_imm((inst), ARM_WORK, __mb_offset); \
+ arm_alu_reg_reg((inst), ARM_ADD, ARM_WORK, (basereg), ARM_WORK); \
+ } \
+ else \
+ { \
+ arm_mov_reg_imm((inst), ARM_WORK, -__mb_offset); \
+ arm_alu_reg_reg((inst), ARM_SUB, ARM_WORK, (basereg), ARM_WORK); \
+ } \
+ arm_inst_add((inst), arm_prefix(0x0D800A00) | \
+ (((unsigned int)ARM_WORK) << 16) | \
+ (((unsigned int)(reg_top_4_bits)) << 12) | \
+ (((unsigned int)(reg_bottom_bit)) << 22)); \
+ } \
+} while (0)
+
+/**
+* FSTD
+*/
#define arm_store_membase_float64(inst,reg,basereg,imm) \
+do { \
+ int __mb_offset = (int)(imm); \
+ if(__mb_offset >= 0 && __mb_offset < (1 << 10) && \
+ (__mb_offset & 3) == 0) \
+ { \
+ arm_inst_add((inst), arm_prefix(0x0D800B00 | \
+ (((unsigned int)(basereg)) << 16) | \
+ (((unsigned int)(reg)) << 12) | \
+ ((unsigned int)((__mb_offset / 4) & 0xFF)))); \
+ } \
+ else if(__mb_offset > -(1 << 10) && __mb_offset < 0 && \
+ (__mb_offset & 3) == 0) \
+ { \
+ arm_inst_add((inst), arm_prefix(0x0D000B00 | \
+ (((unsigned int)(basereg)) << 16) | \
+ (((unsigned int)(reg)) << 12) | \
+ ((unsigned int)(((-__mb_offset) / 4) & 0xFF))));\
+ } \
+ else \
+ { \
+ assert(reg != ARM_WORK); \
+ assert(basereg!=ARM_WORK); \
+ if(__mb_offset > 0) \
+ { \
+ arm_mov_reg_imm((inst), ARM_WORK, __mb_offset); \
+ arm_alu_reg_reg((inst), ARM_ADD, ARM_WORK, (basereg), ARM_WORK); \
+ } \
+ else \
+ { \
+ arm_mov_reg_imm((inst), ARM_WORK, -__mb_offset); \
+ arm_alu_reg_reg((inst), ARM_SUB, ARM_WORK, (basereg), ARM_WORK);\
+ } \
+ arm_inst_add((inst), arm_prefix(0x0D800B00 | \
+ (((unsigned int)ARM_WORK) << 16) | \
+ (((unsigned int)(reg)) << 12)));\
+ } \
+} while (0)
+
+/*
+ * Floating point push/pop operations
+ */
+#define arm_push_reg_float64(inst,reg) \
do { \
- arm_store_membase_float((inst), (reg), (basereg), \
- (imm), 0x00008000); \
+ arm_store_membase_float64((inst), (reg), ARM_SP, -8); \
+ arm_alu_reg_imm(inst, ARM_SUB, ARM_SP, ARM_SP, 8); \
} while (0)
+
#define arm_push_reg_float32(inst,reg) \
do { \
- arm_store_membase_float((inst), (reg), ARM_SP, \
- -4, 0x00200000); \
- } while (0)
-#define arm_push_reg_float64(inst,reg) \
- do { \
- arm_store_membase_float((inst), (reg), ARM_SP, \
- -4, 0x00208000); \
+ arm_store_membase_float32((inst), (reg), ARM_SP, -4); \
+ arm_alu_reg_imm(inst, ARM_SUB, ARM_SP, ARM_SP, 4); \
} while (0)
/*
@@ -996,6 +1499,103 @@
(basereg), (indexreg)); \
} while (0)
+
+/**
+ * FMDRR (Floating-point Move to Double-precision Register from two Registers)
+ * Move a value from two ARM registers (lowsreg, highsreg) to a double-precision floating point register (dreg)
+ */
+#define arm_mov_double_reg_reg(inst,dreg,lowsreg,highsreg) \
+do { \
+ arm_inst_add((inst), arm_prefix(0x0C400B10) | \
+ (((unsigned int)(lowsreg)) << 12) | \
+ (((unsigned int)(highsreg)) << 16) | \
+ ((unsigned int)(dreg))); \
+} while(0)
+
+/**
+* FMRRD (Floating-point Move to two registers from Double-precision Register)
+* Move a value from a double-precision floating point register (sreg) to two ARM registers (lowsreg, highsreg)
+*/
+#define arm_mov_reg_reg_double(inst,lowsreg,highsreg,sreg) \
+do { \
+ arm_inst_add((inst), arm_prefix(0x0C500B10) | \
+ (((unsigned int)(lowsreg)) << 12) | \
+ (((unsigned int)(highsreg)) << 16) | \
+ ((unsigned int)(sreg))); \
+} while(0)
+
+/**
+ * FMSR (Floating-point Move to Single-precision from Register)
+ * Move a value from one ARM registers (sreg) to a single-precision floating point register (dreg)
+ */
+#define arm_mov_float_reg(inst,dreg,sreg) \
+do { \
+ char dreg_top_4_bits = (dreg & 0x1E) >> 1; \
+ char dreg_bottom_bit = (dreg & 0x01); \
+ arm_inst_add((inst), arm_prefix(0x0E000A10) | \
+ (((unsigned int)(sreg)) << 12) | \
+ (((unsigned int)(dreg_top_4_bits)) << 16) | \
+ (((unsigned int)(dreg_bottom_bit)) << 7)); \
+} while(0)
+
+/**
+* FMRS (Floating-point Move to Register from Single-precision)
+* Move a value from a single-precision floating point register (sreg) to an ARM registers (dreg)
+*/
+#define arm_mov_reg_float(inst,dreg,sreg) \
+do { \
+ char sreg_top_4_bits = (dreg & 0x1E) >> 1; \
+ char sreg_bottom_bit = (dreg & 0x01); \
+ arm_inst_add((inst), arm_prefix(0x0E100A10) | \
+ (((unsigned int)(dreg)) << 12) | \
+ (((unsigned int)(sreg_top_4_bits)) << 16) | \
+ (((unsigned int)(sreg_bottom_bit)) << 7)); \
+} while(0)
+
+/**
+* FCVTDS (Floating-point Convert to Double-precision from Single-precision)
+* dreg is the double precision destination register
+* sreg is the single precision source register
+*/
+#define arm_convert_float_double_single(inst,dreg,sreg) \
+{ \
+ unsigned char sreg_top_4_bits = (sreg & 0x1E) >> 1; \
+ unsigned char sreg_bottom_bit = (sreg & 0x01); \
+ arm_inst_add((inst), arm_prefix(0x0EB70AC0) | \
+ (((unsigned int)(sreg_top_4_bits))) | \
+ (((unsigned int)(sreg_bottom_bit)) << 5) | \
+ (((unsigned int)(dreg)) << 12)); \
+}
+
+/**
+ * FCVTSD (Floating-point Convert to Single-precision from Double-precision)
+ * dreg is the single precision destination register
+ * sreg is the double precision source register
+ */
+#define arm_convert_float_single_double(inst,dreg,sreg) \
+{ \
+ unsigned char dreg_top_4_bits = (dreg & 0x1E) >> 1; \
+ unsigned char dreg_bottom_bit = (dreg & 0x01); \
+ arm_inst_add((inst), arm_prefix(0x0EB70BC0) | \
+ (((unsigned int)(dreg_top_4_bits)) << 12) | \
+ (((unsigned int)(dreg_bottom_bit)) << 22) | \
+ ((unsigned int)(sreg))); \
+}
+
+/**
+ * FSITOD (Floating-point Convert Signed Integer to Double-precision)
+ * sreg is the single precision register containing the integer value to be converted
+ * dreg is the double precision destination register
+ */
+#define arm_convert_float_signed_integer_double(inst,dreg,sreg) \
+ unsigned char sreg_top_4_bits = (sreg & 0x1E) >> 1; \
+ unsigned char sreg_bottom_bit = (sreg & 0x01); \
+ arm_inst_add((inst), arm_prefix(0x0EB80BC0) | \
+ (((unsigned int)(dreg)) << 12) | \
+ (((unsigned int)(sreg_bottom_bit)) << 5) | \
+ ((unsigned int)(sreg_top_4_bits)));
+
+
#ifdef __cplusplus
};
#endif
diff -ruN libjit/jit/jit-reg-alloc.c libjit-mikyt/jit/jit-reg-alloc.c
--- libjit/jit/jit-reg-alloc.c 2008-07-06 11:07:18.000000000 +0200
+++ libjit-mikyt/jit/jit-reg-alloc.c 2009-01-26 20:51:25.000000000 +0100
@@ -160,6 +160,28 @@
return -1;
}
+/**
+ * Given the only register known, returns both the registers (if coupled) or the register and -1
+ *
+ * @var reg The register known (on entry). The same value or the value of the first register in the couple (on exit).
+ * @var other_reg The content is ignored on entry. On exit, it contains the second register in a couple or -1 if there is no second register.
+ */
+void get_reg_and_other_reg(jit_gencode_t gen, int *reg, int *other_reg)
+{
+ if(gen->contents[*reg].is_long_start)
+ {
+ *other_reg = OTHER_REG(*reg);
+ }
+ else if(gen->contents[*reg].is_long_end)
+ {
+ *other_reg = *reg;
+ *reg = get_long_pair_start(*reg);
+ }
+ else
+ {
+ *other_reg = -1;
+ }
+}
/*
* Determine the type of register that we need.
*/
@@ -1829,7 +1851,7 @@
abort();
}
#endif
-
+
gen->contents[reg].values[gen->contents[reg].num_values] = value;
++(gen->contents[reg].num_values);
gen->contents[reg].age = gen->current_age;
@@ -1849,7 +1871,7 @@
gen->contents[other_reg].is_long_end = 1;
}
++(gen->current_age);
-
+
/* Adjust the value to reflect that it is in "reg", and maybe the frame */
value->in_register = 1;
if(value->has_global_register)
@@ -2964,6 +2986,14 @@
++(gen->reg_stack_top);
}
#endif
+#if defined(JIT_BACKEND_ARM) && defined(JIT_ARM_HAS_FLOAT_REGS)
+ /*
+ * On the ARM platform, the results of a function call are always in r0-r3,
+ * even when the result is float or double.
+ * so we must take care of handling this situation correctly
+ */
+ return_to_float(gen, value, reg);
+#endif
bind_value(gen, value, reg, other_reg, 0);
}
@@ -3033,6 +3063,14 @@
}
_jit_gen_load_value(gen, reg, other_reg, value);
+#ifdef JIT_BACKEND_ARM
+ if(jit_type_get_kind(jit_value_get_type(value))==JIT_TYPE_STRUCT)
+ {
+ //_jit_gen_load_value doesn't handle structs
+ _jit_gen_load_value_struct (gen, reg, value);
+ }
+#endif
+
}
jit_reg_set_used(gen->inhibit, reg);
@@ -3808,8 +3846,8 @@
}
commit_output_value(gen, regs, 0);
}
- else
#endif
+ else
{
commit_input_value(gen, regs, 2, 0);
commit_input_value(gen, regs, 1, 0);
diff -ruN libjit/jit/jit-reg-alloc.h libjit-mikyt/jit/jit-reg-alloc.h
--- libjit/jit/jit-reg-alloc.h 2008-01-24 21:12:53.000000000 +0100
+++ libjit-mikyt/jit/jit-reg-alloc.h 2008-12-05 10:32:16.000000000 +0100
@@ -190,6 +190,7 @@
unsigned char *_jit_regs_begin(jit_gencode_t gen, _jit_regs_t *regs, int space);
void _jit_regs_end(jit_gencode_t gen, _jit_regs_t *regs, unsigned char *inst);
+void get_reg_and_other_reg(jit_gencode_t gen, int *reg, int *other_reg);
#ifdef __cplusplus
};
#endif
diff -ruN libjit/jit/jit-rules-arm.c libjit-mikyt/jit/jit-rules-arm.c
--- libjit/jit/jit-rules-arm.c 2008-01-24 21:12:53.000000000 +0100
+++ libjit-mikyt/jit/jit-rules-arm.c 2009-02-05 11:59:56.000000000 +0100
@@ -2,6 +2,7 @@
* jit-rules-arm.c - Rules that define the characteristics of the ARM.
*
* Copyright (C) 2004 Southern Storm Software, Pty Ltd.
+ * Copyright (C) 2008 Michele Tartara
*
* This file is part of the libjit library.
*
@@ -32,40 +33,200 @@
#include
/*
+ * Pseudo register numbers for the ARM registers. These are not the
+ * same as the CPU instruction register numbers. The order of these
+ * values must match the order in "JIT_REG_INFO".
+ */
+#define ARM_REG_R0 0
+#define ARM_REG_R1 1
+#define ARM_REG_R2 2
+#define ARM_REG_R3 3
+#define ARM_REG_R4 4
+#define ARM_REG_R5 5
+#define ARM_REG_R6 6
+#define ARM_REG_R7 7
+#define ARM_REG_R8 8
+#define ARM_REG_R9 9
+#define ARM_REG_R10 10
+#define ARM_REG_FP 11
+#define ARM_REG_R12 12
+#define ARM_REG_SP 13
+#define ARM_REG_LR 14
+#define ARM_REG_PC 15
+#define ARM_REG_S0 16
+#define ARM_REG_S1 17
+#define ARM_REG_S2 18
+#define ARM_REG_S3 19
+#define ARM_REG_S4 20
+#define ARM_REG_S5 21
+#define ARM_REG_S6 22
+#define ARM_REG_S7 23
+#define ARM_REG_S8 24
+#define ARM_REG_S9 25
+#define ARM_REG_S10 26
+#define ARM_REG_S11 27
+#define ARM_REG_S12 28
+#define ARM_REG_S13 29
+#define ARM_REG_S14 30
+#define ARM_REG_S15 31
+#define ARM_REG_D8 32
+#define ARM_REG_D9 33
+#define ARM_REG_D10 34
+#define ARM_REG_D11 35
+#define ARM_REG_D12 36
+#define ARM_REG_D13 37
+#define ARM_REG_D14 38
+#define ARM_REG_D15 39
+
+ /*
+ * Determine if a pseudo register number is word-based or float-based.
+ */
+#define IS_WORD_REG(reg) ((reg) < ARM_REG_S0)
+#define IS_FLOAT_REG(reg) ((reg) >= ARM_REG_S0)
+
+/*
* Round a size up to a multiple of the stack word size.
*/
#define ROUND_STACK(size) \
(((size) + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1))
+/*
+ * Define the classes of registers
+ */
+static _jit_regclass_t *arm_reg;
+static _jit_regclass_t *arm_freg32;
+static _jit_regclass_t *arm_freg64;
+static _jit_regclass_t *arm_lreg;
+static _jit_regclass_t *arm_breg;
+
/*
+ * -------------------- Helper functions --------------------------
+ */
+/**
* Load the instruction pointer from the generation context.
*/
#define jit_gen_load_inst_ptr(gen,inst) \
do { \
arm_inst_buf_init((inst), (gen)->posn.ptr, (gen)->posn.limit); \
- } while (0)
+} while (0)
-/*
+/**
* Save the instruction pointer back to the generation context.
*/
#define jit_gen_save_inst_ptr(gen,inst) \
do { \
(gen)->posn.ptr = (unsigned char *)arm_inst_get_posn(inst); \
- } while (0)
+} while (0)
-void _jit_init_backend(void)
+/*
+* Get a temporary register that isn't one of the specified registers.
+* When this function is used EVERY REGISTER COULD BE DESTROYED!!!
+* TODO: this function is only used by JIT_OP_STORE_RELATIVE_STRUCT, through memory_copy: remove
+* the need of using it by sustituting it with register allocation with [scratch reg]
+*/
+static int get_temp_reg(int reg1, int reg2, int reg3)
{
- /* Nothing to do here */
+ /*
+ * R0-R3 are not used because they could be needed for parameter passing.
+ * R4 is not used because it's used by jit_apply to store the base of the frame where
+ * it saves all the data it needs in order to restart execution after calling a compiled function.
+ * R9 is not used because it's the platform register and could have special
+ * uses on some ARM platform
+ * R11, R13-R15 are not used because they have special meaning on the ARM platform.
+ * The other registers are candidates for
+ */
+ if(reg1 != ARM_R5 && reg2 != ARM_R5 && reg3 != ARM_R5)
+ {
+ return ARM_R5;
+ }
+ if(reg1 != ARM_R6 && reg2 != ARM_R6 && reg3 != ARM_R6)
+ {
+ return ARM_R6;
+ }
+ if(reg1 != ARM_R7 && reg2 != ARM_R7 && reg3 != ARM_R7)
+ {
+ return ARM_R7;
+ }
+ if(reg1 != ARM_R8 && reg2 != ARM_R8 && reg3 != ARM_R8)
+ {
+ return ARM_R8;
+ }
+ if(reg1 != ARM_R10 && reg2 != ARM_R10 && reg3 != ARM_R10)
+ {
+ return ARM_R10;
+ }
+ return ARM_R12;
}
-void _jit_gen_get_elf_info(jit_elf_info_t *info)
-{
- info->machine = 40; /* EM_ARM */
- info->abi = 0; /* ELFOSABI_SYSV */
- info->abi_version = 0;
-}
+static void mov_reg_imm (jit_gencode_t gen, arm_inst_buf *inst, int reg, int value);
/*
+* Copy a block of memory that has a specific size. Other than
+* the parameter pointers, all registers must be unused at this point.
+*/
+static arm_inst_buf memory_copy (jit_gencode_t gen, arm_inst_buf inst, int dreg, jit_nint doffset, int sreg, jit_nint soffset, jit_nuint size, int temp_reg)
+{
+ //int temp_reg = get_temp_reg(dreg, sreg, -1);
+ if (temp_reg==-1) temp_reg = get_temp_reg(dreg, sreg, -1);
+ if(size <= 4 * sizeof(void *))
+ {
+ /* Use direct copies to copy the memory */
+ int offset = 0;
+ while(size >= sizeof(void *))
+ {
+ arm_mov_reg_membase(inst, temp_reg, sreg, soffset + offset, sizeof(void *));
+ arm_mov_membase_reg(inst, dreg, doffset + offset, temp_reg, sizeof(void *));
+ size -= sizeof(void *);
+ offset += sizeof(void *);
+ }
+ if(size >= 2)
+ {
+ arm_mov_reg_membase(inst, temp_reg, sreg, soffset + offset, 2);
+ arm_mov_membase_reg(inst, dreg, doffset + offset, temp_reg, 2);
+ size -= 2;
+ offset += 2;
+ }
+ if(size >= 1)
+ {
+ arm_mov_reg_membase(inst, temp_reg, sreg, soffset + offset, 1);
+ arm_mov_membase_reg(inst, dreg, doffset + offset, temp_reg, 1);
+ }
+ }
+ else
+ {
+ /* Call out to "jit_memcpy" to effect the copy */
+ //Load the parameters in the right registers
+ //R2 <- size
+ mov_reg_imm(gen, &inst, ARM_R2, size);
+ //R1 <- source pointer
+ if(soffset == 0)
+ {
+ arm_mov_reg_reg(inst, ARM_R1, sreg);
+ }
+ else
+ {
+ arm_alu_reg_imm(inst, ARM_ADD, temp_reg, sreg, soffset);
+ arm_mov_reg_reg(inst, ARM_R1, temp_reg);
+ }
+ //R0 <- destination pointer
+ /* On ARM, the stack doesn't need special treatment, since parameters are passed using registers, not using the stack as it's done on x86 */
+
+ if(doffset == 0)
+ {
+ arm_mov_reg_reg(inst, ARM_R0, dreg);
+ }
+ else
+ {
+ arm_alu_reg_imm(inst, ARM_ADD, temp_reg, dreg, doffset);
+ arm_mov_reg_reg(inst, ARM_R0, temp_reg);
+ }
+
+ arm_call(inst, jit_memcpy);
+ }
+ return inst;
+}
+
+/**
* Flush the contents of the constant pool.
*/
static void flush_constants(jit_gencode_t gen, int after_epilog)
@@ -126,7 +287,7 @@
}
if(value)
{
- fixup -= value;
+ fixup -= value / sizeof(void *);
}
else
{
@@ -148,14 +309,14 @@
jit_gen_save_inst_ptr(gen, inst);
}
-/*
+/**
* Perform a constant pool flush if we are too far from the starting point.
*/
static int flush_if_too_far(jit_gencode_t gen)
{
if(gen->first_constant_use &&
- (((arm_inst_word *)(gen->posn.ptr)) -
- ((arm_inst_word *)(gen->first_constant_use))) >= 100)
+ (((arm_inst_word *)(gen->posn.ptr)) -
+ ((arm_inst_word *)(gen->first_constant_use))) >= 100)
{
flush_constants(gen, 0);
return 1;
@@ -170,7 +331,7 @@
* Add a fixup for a particular constant pool entry.
*/
static void add_constant_fixup
- (jit_gencode_t gen, int index, arm_inst_word *fixup)
+ (jit_gencode_t gen, int index, arm_inst_word *fixup)
{
arm_inst_word *prev;
int value;
@@ -182,7 +343,7 @@
prev = gen->fixup_constants[index];
if(prev)
{
- value = fixup - prev;
+ value = (fixup - prev) * sizeof(void *);
}
else
{
@@ -190,10 +351,12 @@
}
if((*fixup & 0x0F000000) == 0x05000000)
{
+ //Word fixup
*fixup = ((*fixup & ~0x0FFF) | value);
}
else
{
+ //Float fixup
*fixup = ((*fixup & ~0x00FF) | (value / 4));
}
gen->fixup_constants[index] = fixup;
@@ -235,10 +398,10 @@
}
/*
- * Add a double-word immedite value to the constant pool.
+ * Add a double-word immediate value to the constant pool.
*/
static void add_constant_dword
- (jit_gencode_t gen, int value1, int value2, arm_inst_word *fixup, int align)
+ (jit_gencode_t gen, int value1, int value2, arm_inst_word *fixup, int align)
{
int index;
@@ -252,7 +415,7 @@
for(index = 0; index < (gen->num_constants - 1); ++index)
{
if(gen->constants[index] == value1 &&
- gen->constants[index + 1] == value2)
+ gen->constants[index + 1] == value2)
{
if(!align || (index % 2) == 0)
{
@@ -279,8 +442,8 @@
/* Add the double word constant value to the pool */
gen->constants[gen->num_constants] = value1;
gen->fixup_constants[gen->num_constants] = 0;
- gen->constants[gen->num_constants] = value2;
- gen->fixup_constants[gen->num_constants] = 0;
+ gen->constants[gen->num_constants+1] = value2;
+ gen->fixup_constants[gen->num_constants+1] = 0;
gen->num_constants += 2;
add_constant_fixup(gen, gen->num_constants - 2, fixup);
}
@@ -290,7 +453,7 @@
* complicated, then add an entry to the constant pool.
*/
static void mov_reg_imm
- (jit_gencode_t gen, arm_inst_buf *inst, int reg, int value)
+ (jit_gencode_t gen, arm_inst_buf *inst, int reg, int value)
{
arm_inst_word *fixup;
@@ -316,7 +479,7 @@
* complicated, then add an entry to the constant pool.
*/
static void mov_freg_imm_32
- (jit_gencode_t gen, arm_inst_buf *inst, int reg, int value)
+ (jit_gencode_t gen, arm_inst_buf *inst, int reg, int value)
{
arm_inst_word *fixup;
@@ -335,7 +498,7 @@
* complicated, then add an entry to the constant pool.
*/
static void mov_freg_imm_64
- (jit_gencode_t gen, arm_inst_buf *inst, int reg, int value1, int value2)
+ (jit_gencode_t gen, arm_inst_buf *inst, int reg, int value1, int value2)
{
arm_inst_word *fixup;
@@ -349,6 +512,198 @@
jit_gen_load_inst_ptr(gen, *inst);
}
+/*
+ * Output a branch instruction.
+ */
+static void output_branch
+ (jit_function_t func, arm_inst_buf *inst, int cond, jit_insn_t insn)
+{
+ jit_block_t block;
+ int offset;
+ //block = jit_block_from_label(func, (jit_label_t)(insn->dest));
+ if((insn->flags & JIT_INSN_VALUE1_IS_LABEL) != 0)
+ {
+ /* "address_of_label" instruction */
+ block = jit_block_from_label(func, (jit_label_t)(insn->value1));
+ }
+ else
+ {
+ block = jit_block_from_label(func, (jit_label_t)(insn->dest));
+ }
+ if(!block)
+ {
+ return;
+ }
+ if(arm_inst_get_posn(*inst) >= arm_inst_get_limit(*inst))
+ {
+ /* The buffer has overflowed, so don't worry about fixups */
+ return;
+ }
+ if(block->address)
+ {
+ /* We already know the address of the block */
+ arm_branch(*inst, cond, block->address);
+ }
+ else
+ {
+ /* Output a placeholder and record on the block's fixup list */
+ if(block->fixup_list)
+ {
+ offset = (int)(((unsigned char *)arm_inst_get_posn(*inst)) -
+ ((unsigned char *)(block->fixup_list)));
+ }
+ else
+ {
+ offset = 0;
+ }
+ arm_branch_imm(*inst, cond, offset);
+ block->fixup_list = (void *)(arm_inst_get_posn(*inst) - 1);
+ }
+}
+
+/*
+ * Throw a builtin exception.
+ */
+static void throw_builtin
+ (arm_inst_buf *inst, jit_function_t func, int cond, int type)
+{
+ arm_inst_word *patch;
+
+ /* Branch past the following code if "cond" is not true */
+ patch = arm_inst_get_posn(*inst);
+ arm_branch_imm(*inst, cond ^ 0x01, 0);
+
+ /* We need to update "catch_pc" if we have a "try" block */
+ if(func->builder->setjmp_value != 0)
+ {
+ _jit_gen_fix_value(func->builder->setjmp_value);
+ arm_mov_reg_reg(*inst, ARM_WORK, ARM_PC);
+ arm_store_membase(*inst, ARM_WORK, ARM_FP,
+ func->builder->setjmp_value->frame_offset +
+ jit_jmp_catch_pc_offset);
+ }
+
+ /* Push the exception type onto the stack */
+ arm_mov_reg_imm(*inst, ARM_WORK, type);
+ arm_push_reg(*inst, ARM_WORK);
+
+ /* Call the "jit_exception_builtin" function, which will never return */
+ arm_call(*inst, jit_exception_builtin);
+
+ /* Back-patch the previous branch instruction */
+ arm_patch(*inst, patch, arm_inst_get_posn(*inst));
+}
+
+/*
+ * Jump to the current function's epilog.
+ */
+static void jump_to_epilog
+ (jit_gencode_t gen, arm_inst_buf *inst, jit_block_t block)
+{
+ int offset;
+
+ /* If the epilog is the next thing that we will output,
+ then fall through to the epilog directly */
+ block = block->next;
+ while(block != 0 && block->first_insn > block->last_insn)
+ {
+ block = block->next;
+ }
+ if(!block)
+ {
+ return;
+ }
+
+ /* Bail out if the instruction buffer has overflowed */
+ if(arm_inst_get_posn(*inst) >= arm_inst_get_limit(*inst))
+ {
+ return;
+ }
+
+ /* Output a placeholder for the jump and add it to the fixup list */
+ if(gen->epilog_fixup)
+ {
+ offset = (int)(((unsigned char *)arm_inst_get_posn(*inst)) -
+ ((unsigned char *)(gen->epilog_fixup)));
+ }
+ else
+ {
+ offset = 0;
+ }
+ arm_branch_imm(*inst, ARM_CC_AL, offset);
+ gen->epilog_fixup = (void *)(arm_inst_get_posn(*inst) - 1);
+}
+
+#define TODO() \
+ do { \
+ fprintf(stderr, "TODO at %s, %d\n", __FILE__, (int)__LINE__); \
+} while (0)
+
+/*
+ * -------------------- End of helper functions ------------------------
+ */
+
+
+
+/**
+ * Initialize the backend.
+ */
+void _jit_init_backend(void)
+{
+ /*
+ * Init the various classes of registers
+ */
+ /** WORD registers */
+ arm_reg = _jit_regclass_create(
+ "reg", JIT_REG_WORD, 9,
+ ARM_REG_R0, ARM_REG_R1,
+ ARM_REG_R2, ARM_REG_R3,
+ ARM_REG_R4, ARM_REG_R5,
+ ARM_REG_R6, ARM_REG_R7,
+ ARM_REG_R8);
+
+ /** 32-bits float registers */
+ arm_freg32 = _jit_regclass_create(
+ "freg32", JIT_REG_ARM_FLOAT32, 16,
+ ARM_REG_S0, ARM_REG_S1,
+ ARM_REG_S2, ARM_REG_S3,
+ ARM_REG_S4, ARM_REG_S5,
+ ARM_REG_S6, ARM_REG_S7,
+ ARM_REG_S8, ARM_REG_S9,
+ ARM_REG_S10, ARM_REG_S11,
+ ARM_REG_S12, ARM_REG_S13,
+ ARM_REG_S14, ARM_REG_S15);
+
+ /** 64-bits float registers */
+ arm_freg64 = _jit_regclass_create(
+ "freg64", JIT_REG_ARM_FLOAT64, 8,
+ ARM_REG_D8, ARM_REG_D9,
+ ARM_REG_D10, ARM_REG_D11,
+ ARM_REG_D12, ARM_REG_D13,
+ ARM_REG_D14, ARM_REG_D15);
+
+ /** Long registers */
+ arm_lreg = _jit_regclass_create(
+ "lreg", JIT_REG_LONG, 2,
+ ARM_REG_R0, ARM_REG_R2);
+
+ /** byte registers */ //TODO: probably useless on ARM. Just substitute every use of breg with a use of reg
+ arm_breg = _jit_regclass_create(
+ "breg", JIT_REG_WORD, 9,
+ ARM_REG_R0, ARM_REG_R1,
+ ARM_REG_R2, ARM_REG_R3,
+ ARM_REG_R4, ARM_REG_R5,
+ ARM_REG_R6, ARM_REG_R7,
+ ARM_REG_R8);
+}
+
+void _jit_gen_get_elf_info(jit_elf_info_t *info)
+{
+ info->machine = 40; /* EM_ARM */
+ info->abi = 0; /* ELFOSABI_SYSV */
+ info->abi_version = 0;
+}
+
int _jit_setup_indirect_pointer(jit_function_t func, jit_value_t value)
{
return jit_insn_outgoing_reg(func, value, ARM_WORK);
@@ -367,7 +722,7 @@
ptr_return = jit_type_return_via_pointer(return_type);
if(!return_value || ptr_return)
{
- return 0;
+ return 1;
}
/* Structure values must be flushed into the frame, and
@@ -380,11 +735,18 @@
}
}
#ifdef JIT_ARM_HAS_FLOAT_REGS
- else if(return_type->kind == JIT_TYPE_FLOAT32 ||
- return_type->kind == JIT_TYPE_FLOAT64 ||
+ //TODO: check that this works when the handling of the float registers changes
+ else if(return_type->kind == JIT_TYPE_FLOAT32)
+ {
+ if(!jit_insn_return_reg(func, return_value, ARM_REG_S0))
+ {
+ return 0;
+ }
+ }
+ else if(return_type->kind == JIT_TYPE_FLOAT64 ||
return_type->kind == JIT_TYPE_NFLOAT)
{
- if(!jit_insn_return_reg(func, return_value, 16 /* f0 */))
+ if(!jit_insn_return_reg(func, return_value, ARM_REG_D8))
{
return 0;
}
@@ -392,7 +754,7 @@
#endif
else if(return_type->kind != JIT_TYPE_VOID)
{
- if(!jit_insn_return_reg(func, return_value, 0 /* r0 */))
+ if(!jit_insn_return_reg(func, return_value, ARM_REG_R0))
{
return 0;
}
@@ -407,7 +769,7 @@
switch(opcode)
{
#define JIT_INCLUDE_SUPPORTED
- #include "jit-rules-arm.slc"
+ #include "jit-rules-arm.inc"
#undef JIT_INCLUDE_SUPPORTED
}
return 0;
@@ -420,7 +782,8 @@
int reg, regset;
unsigned int saved;
unsigned int frame_size;
-
+ unsigned int stack_growth;
+
/* Initialize the instruction buffer */
arm_inst_buf_init(inst, prolog, prolog + JIT_PROLOG_SIZE / sizeof(int));
@@ -443,8 +806,26 @@
/* Allocate space for the local variable frame. Subtract off
the space for the registers that we just saved. The pc, lr,
and fp registers are always saved, so account for them too */
+ stack_growth=(saved + 4 * sizeof(void *));
+ frame_size = func->builder->frame_size - stack_growth;
frame_size = func->builder->frame_size - (saved + 3 * sizeof(void *));
frame_size += (unsigned int)(func->builder->param_area_size);
+ while(frame_size % JIT_SP_ALIGN_PUBLIC != 0)
+ {
+ //Pad to reach the required stacl pointer alignment
+ frame_size++;
+ }
+
+ /* If the registers that get saved on the stack make it grow of a odd number
+ * of words, the preceding while isn't able anymore to compute the correct
+ * allignment. The following adds a correction when needed.
+ */
+ if (stack_growth % JIT_SP_ALIGN_PUBLIC != 0)
+ {
+ //Pad to reach the required stack pointer alignment
+ frame_size += (stack_growth % JIT_SP_ALIGN_PUBLIC);
+ }
+
if(frame_size > 0)
{
arm_alu_reg_imm(inst, ARM_SUB, ARM_SP, ARM_SP, frame_size);
@@ -504,6 +885,11 @@
flush_constants(gen, 1);
}
+#if 0
+/*
+ * The ARM backend does not need this function because it uses
+ * _jit_create_indirector() instead.
+ */
void *_jit_gen_redirector(jit_gencode_t gen, jit_function_t func)
{
void *ptr, *entry;
@@ -517,7 +903,7 @@
jit_gen_save_inst_ptr(gen, inst);
return entry;
}
-
+#endif
/*
* Setup or teardown the ARM code output process.
*/
@@ -527,6 +913,12 @@
#define jit_cache_end_output() \
jit_gen_save_inst_ptr(gen, inst)
+/**
+ * Spill the content of register "reg" (and "other_reg", if it's different from -1)
+ * into the global register or the memory area associated with "value"
+ * NB: it doesn't set value->in_global_register or value->in_frame. The caller has to
+ * take care of that.
+ */
void _jit_gen_spill_reg(jit_gencode_t gen, int reg,
int other_reg, jit_value_t value)
{
@@ -542,14 +934,21 @@
/* Output an appropriate instruction to spill the value */
if(value->has_global_register)
{
- arm_mov_reg_reg(inst, _jit_reg_info[value->global_reg].cpu_reg,
- _jit_reg_info[reg].cpu_reg);
+ if (IS_FLOAT_REG(reg))
+ {
+ printf("TODO:Copy from float reg to global reg is not handled properly in %s\n", __FILE__);
+ abort();
+ }
+ else
+ {
+ arm_mov_reg_reg(inst, _jit_reg_info[value->global_reg].cpu_reg, _jit_reg_info[reg].cpu_reg);
+ }
}
else
{
_jit_gen_fix_value(value);
offset = (int)(value->frame_offset);
- if(reg < 16)
+ if(IS_WORD_REG(reg))
{
arm_store_membase(inst, reg, ARM_FP, offset);
if(other_reg != -1)
@@ -561,11 +960,11 @@
}
else if(jit_type_normalize(value->type)->kind == JIT_TYPE_FLOAT32)
{
- arm_store_membase_float32(inst, reg - 16, ARM_FP, offset);
+ arm_store_membase_float32(inst, _jit_reg_info[value->reg].cpu_reg, ARM_FP, offset);
}
else
{
- arm_store_membase_float64(inst, reg - 16, ARM_FP, offset);
+ arm_store_membase_float64(inst, _jit_reg_info[value->reg].cpu_reg, ARM_FP, offset);
}
}
@@ -624,7 +1023,7 @@
{
jit_float32 float32_value;
float32_value = jit_value_get_float32_constant(value);
- if(reg < 16)
+ if(IS_WORD_REG(reg))
{
mov_reg_imm(gen, &inst, _jit_reg_info[reg].cpu_reg,
*((int *)&float32_value));
@@ -643,7 +1042,7 @@
{
jit_float64 float64_value;
float64_value = jit_value_get_float64_constant(value);
- if(reg < 16)
+ if(IS_WORD_REG(reg))
{
mov_reg_imm
(gen, &inst, _jit_reg_info[reg].cpu_reg,
@@ -665,6 +1064,26 @@
}
else if(value->has_global_register)
{
+ /*
+ * This value has been assinged a global register. This means
+ * that it can use that register, but not necessarily that it's
+ * already in it!!
+ */
+
+ /* Ensure that the value is already in the global_register */
+ if (!value->in_global_register)
+ {
+ /* Find the other register in a long pair */
+ int reg=value->reg;
+ int other_reg;
+ get_reg_and_other_reg(gen, ®, &other_reg);
+ //Spill to the global register
+ _jit_gen_spill_reg(gen, reg, other_reg, value);
+ value->in_global_register=1;
+
+ /* A new instruction has probably been generated by _jit_gen_spill_reg: reload the inst pointer */
+ jit_gen_load_inst_ptr(gen, inst);
+ }
/* Load the value out of a global register */
arm_mov_reg_reg(inst, _jit_reg_info[reg].cpu_reg,
_jit_reg_info[value->global_reg].cpu_reg);
@@ -675,34 +1094,47 @@
_jit_gen_fix_value(value);
offset = (int)(value->frame_offset);
- /* Load the value into the specified register */
+ /* Ensure that the value is already in the stack frame */
+ if(value->in_register)
+ {
+ /* Find the other register in a long pair */
+ int reg=value->reg;
+ int other_reg;
+ get_reg_and_other_reg(gen, ®, &other_reg);
+ _jit_gen_spill_reg(gen, reg, other_reg, value);
+ value->in_frame=1;
+
+ /* A new instruction has probably been generated by _jit_gen_spill_reg: reload the inst pointer */
+ jit_gen_load_inst_ptr(gen, inst);
+ }
+
switch(jit_type_normalize(value->type)->kind)
{
case JIT_TYPE_SBYTE:
{
arm_load_membase_sbyte(inst, _jit_reg_info[reg].cpu_reg,
- ARM_FP, offset);
+ ARM_FP, offset);
}
break;
case JIT_TYPE_UBYTE:
{
arm_load_membase_byte(inst, _jit_reg_info[reg].cpu_reg,
- ARM_FP, offset);
+ ARM_FP, offset);
}
break;
case JIT_TYPE_SHORT:
{
arm_load_membase_short(inst, _jit_reg_info[reg].cpu_reg,
- ARM_FP, offset);
+ ARM_FP, offset);
}
break;
case JIT_TYPE_USHORT:
{
arm_load_membase_ushort(inst, _jit_reg_info[reg].cpu_reg,
- ARM_FP, offset);
+ ARM_FP, offset);
}
break;
@@ -710,7 +1142,7 @@
case JIT_TYPE_UINT:
{
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg,
- ARM_FP, offset);
+ ARM_FP, offset);
}
break;
@@ -718,18 +1150,18 @@
case JIT_TYPE_ULONG:
{
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg,
- ARM_FP, offset);
+ ARM_FP, offset);
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg + 1,
- ARM_FP, offset + 4);
+ ARM_FP, offset + 4);
}
break;
case JIT_TYPE_FLOAT32:
{
- if(reg < 16)
+ if(IS_WORD_REG(reg))
{
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg,
- ARM_FP, offset);
+ ARM_FP, offset);
}
else
{
@@ -742,12 +1174,12 @@
case JIT_TYPE_FLOAT64:
case JIT_TYPE_NFLOAT:
{
- if(reg < 16)
+ if(IS_WORD_REG(reg))
{
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg,
- ARM_FP, offset);
+ ARM_FP, offset);
arm_load_membase(inst, _jit_reg_info[reg].cpu_reg + 1,
- ARM_FP, offset + 4);
+ ARM_FP, offset + 4);
}
else
{
@@ -763,160 +1195,110 @@
jit_cache_end_output();
}
-void _jit_gen_spill_global(jit_gencode_t gen, int reg, jit_value_t value)
+/**
+ * Loads a struct indicated by "value" into the given register reg
+ */
+void _jit_gen_load_value_struct (jit_gencode_t gen, int reg, jit_value_t value)
{
- /* TODO: Implement if ARM needs it. */
-}
+ int offset;
-void _jit_gen_load_global(jit_gencode_t gen, int reg, jit_value_t value)
-{
+ /* Make sure that we have sufficient space */
jit_cache_setup_output(32);
- arm_load_membase(inst, _jit_reg_info[value->global_reg].cpu_reg,
- ARM_FP, value->frame_offset);
- jit_cache_end_output();
-}
-
-void _jit_gen_exch_top(jit_gencode_t gen, int reg)
-{
-}
-
-void _jit_gen_move_top(jit_gencode_t gen, int reg)
-{
-}
-
-void _jit_gen_spill_top(jit_gencode_t gen, int reg, jit_value_t value, int pop)
-{
-}
-
-void _jit_gen_fix_value(jit_value_t value)
-{
- if(!(value->has_frame_offset) && !(value->is_constant))
+ if(flush_if_too_far(gen))
{
- jit_nint size = (jit_nint)(ROUND_STACK(jit_type_get_size(value->type)));
- value->block->func->builder->frame_size += size;
- value->frame_offset = -(value->block->func->builder->frame_size);
- value->has_frame_offset = 1;
+ jit_gen_load_inst_ptr(gen, inst);
}
-}
-/*
- * Output a branch instruction.
- */
-static void output_branch
- (jit_function_t func, arm_inst_buf *inst, int cond, jit_insn_t insn)
-{
- jit_block_t block;
- int offset;
- block = jit_block_from_label(func, (jit_label_t)(insn->dest));
- if(!block)
+ if(value->is_constant)
{
- return;
+ TODO();
+ abort();
}
- if(arm_inst_get_posn(*inst) >= arm_inst_get_limit(*inst))
- {
- /* The buffer has overflowed, so don't worry about fixups */
- return;
- }
- if(block->address)
+ else if(value->has_global_register)
{
- /* We already know the address of the block */
- arm_branch(*inst, cond, block->address);
+ /*
+ * This value has been assinged a global register. This means
+ * that it can use that register, but not necessarily that it's
+ * already in it!!
+ */
+
+ /* Ensure that the value is already in the global_register */
+ if (!value->in_global_register)
+ {
+ /* Find the other register in a long pair */
+ int reg=value->reg;
+ int other_reg;
+ get_reg_and_other_reg(gen, ®, &other_reg);
+ //Spill to the global register
+ _jit_gen_spill_reg(gen, reg, other_reg, value);
+ value->in_global_register=1;
+
+ /* A new instruction has probably been generated by _jit_gen_spill_reg: reload the inst pointer */
+ jit_gen_load_inst_ptr(gen, inst);
+ }
+ /* Load the value out of a global register */
+ arm_mov_reg_reg(inst, _jit_reg_info[reg].cpu_reg,
+ _jit_reg_info[value->global_reg].cpu_reg);
}
else
{
- /* Output a placeholder and record on the block's fixup list */
- if(block->fixup_list)
+ /* Fix the position of the value in the stack frame */
+ _jit_gen_fix_value(value);
+ offset = (int)(value->frame_offset);
+
+ /* Ensure that the value is already in the stack frame */
+ if(value->in_register)
{
- offset = (int)(((unsigned char *)arm_inst_get_posn(*inst)) -
- ((unsigned char *)(block->fixup_list)));
+ /* Find the other register in a long pair */
+ int reg=value->reg;
+ int other_reg;
+ get_reg_and_other_reg(gen, ®, &other_reg);
+ _jit_gen_spill_reg(gen, reg, other_reg, value);
+ value->in_frame=1;
+
+ /* A new instruction has probably been generated by _jit_gen_spill_reg: reload the inst pointer */
+ jit_gen_load_inst_ptr(gen, inst);
}
- else
+
+ assert(jit_type_normalize(value->type)->kind==JIT_TYPE_STRUCT);
+
+ arm_load_membase(inst, _jit_reg_info[reg].cpu_reg, ARM_FP, offset);
+ if (jit_type_get_size(jit_value_get_type(value)) > 4)
{
- offset = 0;
+ TODO();
+ abort();
}
- arm_branch_imm(*inst, cond, offset);
- block->fixup_list = (void *)(arm_inst_get_posn(*inst) - 1);
+
}
+
+ /* End the code output process */
+ jit_cache_end_output();
}
-/*
- * Throw a builtin exception.
- */
-static void throw_builtin
- (arm_inst_buf *inst, jit_function_t func, int cond, int type)
+void _jit_gen_spill_global(jit_gencode_t gen, int reg, jit_value_t value)
{
- arm_inst_word *patch;
-
- /* Branch past the following code if "cond" is not true */
- patch = arm_inst_get_posn(*inst);
- arm_branch_imm(*inst, cond ^ 0x01, 0);
-
- /* We need to update "catch_pc" if we have a "try" block */
- if(func->builder->setjmp_value != 0)
- {
- _jit_gen_fix_value(func->builder->setjmp_value);
- arm_mov_reg_reg(*inst, ARM_WORK, ARM_PC);
- arm_store_membase(*inst, ARM_WORK, ARM_FP,
- func->builder->setjmp_value->frame_offset +
- jit_jmp_catch_pc_offset);
- }
-
- /* Push the exception type onto the stack */
- arm_mov_reg_imm(*inst, ARM_WORK, type);
- arm_push_reg(*inst, ARM_WORK);
-
- /* Call the "jit_exception_builtin" function, which will never return */
- arm_call(*inst, jit_exception_builtin);
-
- /* Back-patch the previous branch instruction */
- arm_patch(*inst, patch, arm_inst_get_posn(*inst));
+ /* TODO: Implement if ARM needs it. */
}
-/*
- * Jump to the current function's epilog.
- */
-static void jump_to_epilog
- (jit_gencode_t gen, arm_inst_buf *inst, jit_block_t block)
+void _jit_gen_load_global(jit_gencode_t gen, int reg, jit_value_t value)
{
- int offset;
-
- /* If the epilog is the next thing that we will output,
- then fall through to the epilog directly */
- block = block->next;
- while(block != 0 && block->first_insn > block->last_insn)
- {
- block = block->next;
- }
- if(!block)
- {
- return;
- }
-
- /* Bail out if the instruction buffer has overflowed */
- if(arm_inst_get_posn(*inst) >= arm_inst_get_limit(*inst))
- {
- return;
- }
+ jit_cache_setup_output(32);
+ arm_load_membase(inst, _jit_reg_info[value->global_reg].cpu_reg,
+ ARM_FP, value->frame_offset);
+ jit_cache_end_output();
+}
- /* Output a placeholder for the jump and add it to the fixup list */
- if(gen->epilog_fixup)
- {
- offset = (int)(((unsigned char *)arm_inst_get_posn(*inst)) -
- ((unsigned char *)(gen->epilog_fixup)));
- }
- else
+void _jit_gen_fix_value(jit_value_t value)
+{
+ if(!(value->has_frame_offset) && !(value->is_constant))
{
- offset = 0;
+ jit_nint size = (jit_nint)(ROUND_STACK(jit_type_get_size(value->type)));
+ value->block->func->builder->frame_size += size;
+ value->frame_offset = -(value->block->func->builder->frame_size);
+ value->has_frame_offset = 1;
}
- arm_branch_imm(*inst, ARM_CC_AL, offset);
- gen->epilog_fixup = (void *)(arm_inst_get_posn(*inst) - 1);
}
-#define TODO() \
- do { \
- fprintf(stderr, "TODO at %s, %d\n", __FILE__, (int)__LINE__); \
- } while (0)
-
void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
jit_block_t block, jit_insn_t insn)
{
@@ -924,7 +1306,7 @@
switch(insn->opcode)
{
#define JIT_INCLUDE_RULES
- #include "jit-rules-arm.slc"
+ #include "jit-rules-arm.inc"
#undef JIT_INCLUDE_RULES
default:
@@ -985,4 +1367,27 @@
return 0;
}
+/** "value" is a float value (single or double) that has just been returned
+ * by a function and is in r0 (and, if needed, r1).
+ * If it is a float value, this function puts it back where it should be, in the float register reg
+ * (of appropriate size)
+ */
+void return_to_float(jit_gencode_t gen, jit_value_t value, int reg)
+{
+ if (IS_FLOAT_REG(reg))
+ {
+ arm_inst_buf inst;
+ jit_gen_load_inst_ptr(gen, inst);
+
+ if (value->type->kind==JIT_TYPE_FLOAT64||value->type->kind==JIT_TYPE_NFLOAT)
+ {
+ arm_mov_double_reg_reg(inst, _jit_reg_info[reg].cpu_reg,0,1);
+ }
+ else if (value->type->kind==JIT_TYPE_FLOAT32)
+ {
+ arm_mov_float_reg(inst, _jit_reg_info[reg].cpu_reg,0);
+ }
+ jit_gen_save_inst_ptr(gen, inst);
+ }
+}
#endif /* JIT_BACKEND_ARM */
diff -ruN libjit/jit/jit-rules-arm.h libjit-mikyt/jit/jit-rules-arm.h
--- libjit/jit/jit-rules-arm.h 2008-01-24 21:12:53.000000000 +0100
+++ libjit-mikyt/jit/jit-rules-arm.h 2009-01-26 20:51:25.000000000 +0100
@@ -2,6 +2,7 @@
* jit-rules-arm.h - Rules that define the characteristics of the ARM.
*
* Copyright (C) 2004 Southern Storm Software, Pty Ltd.
+ * Copyright (C) 2008 Michele Tartara
*
* This file is part of the libjit library.
*
@@ -40,16 +41,18 @@
* Information about all of the registers, in allocation order.
* We use r0-r5 for general-purpose values and r6-r8 for globals.
*
- * Of the floating-point registers, we only use f0-f3 at present,
- * so that we don't have to worry about saving the values of f4-f7.
* The floating-point registers are only present on some ARM cores.
+ *
+ * The definitions of the used flags are in jit-rules.h
*/
#ifdef JIT_ARM_HAS_FLOAT_REGS
- #define JIT_REG_ARM_FLOAT \
- (JIT_REG_FLOAT32 | JIT_REG_FLOAT64 | JIT_REG_NFLOAT | JIT_REG_CALL_USED)
+ #define JIT_REG_ARM_FLOAT32 (JIT_REG_FLOAT32)
+ #define JIT_REG_ARM_FLOAT64 (JIT_REG_FLOAT64 | JIT_REG_NFLOAT)
#else
- #define JIT_REG_ARM_FLOAT JIT_REG_FIXED
+ #define JIT_REG_ARM_FLOAT32 (JIT_REG_FIXED | JIT_REG_CALL_USED)
+ #define JIT_REG_ARM_FLOAT64 (JIT_REG_FIXED | JIT_REG_CALL_USED)
#endif
+
#define JIT_REG_INFO \
{"r0", 0, 1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_CALL_USED}, \
{"r1", 1, -1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
@@ -67,13 +70,38 @@
{"sp", 13, -1, JIT_REG_FIXED | JIT_REG_STACK_PTR}, \
{"lr", 14, -1, JIT_REG_FIXED}, \
{"pc", 15, -1, JIT_REG_FIXED}, \
- {"f0", 0, -1, JIT_REG_ARM_FLOAT}, \
- {"f1", 1, -1, JIT_REG_ARM_FLOAT}, \
- {"f2", 2, -1, JIT_REG_ARM_FLOAT}, \
- {"f3", 3, -1, JIT_REG_ARM_FLOAT},
-#define JIT_NUM_REGS 20
+ {"s0", 0, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s1", 1, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s2", 2, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s3", 3, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s4", 4, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s5", 5, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s6", 6, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s7", 7, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s8", 8, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s9", 9, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s10", 10, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s11", 11, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s12", 12, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s13", 13, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s14", 14, -1, JIT_REG_ARM_FLOAT32}, \
+ {"s15", 15, -1, JIT_REG_ARM_FLOAT32}, \
+ {"d8", 8, -1, JIT_REG_ARM_FLOAT64}, \
+ {"d9", 9, -1, JIT_REG_ARM_FLOAT64}, \
+ {"d10", 10, -1, JIT_REG_ARM_FLOAT64}, \
+ {"d11", 11, -1, JIT_REG_ARM_FLOAT64}, \
+ {"d12", 12, -1, JIT_REG_ARM_FLOAT64}, \
+ {"d13", 13, -1, JIT_REG_ARM_FLOAT64}, \
+ {"d14", 14, -1, JIT_REG_ARM_FLOAT64}, \
+ {"d15", 15, -1, JIT_REG_ARM_FLOAT64},
+
+//JIT_NUM_REGS is the total number of registers
+#define JIT_NUM_REGS 40
#define JIT_NUM_GLOBAL_REGS 3
+//Floating point registers are NOT handled like a stack
+#undef JIT_REG_STACK
+
/*
* Define to 1 if we should always load values into registers
* before operating on them. i.e. the CPU does not have reg-mem
@@ -90,7 +118,7 @@
/*
* Preferred alignment for the start of functions.
*/
-#define JIT_FUNCTION_ALIGNMENT 4
+#define JIT_FUNCTION_ALIGNMENT 8
/*
* Define this to 1 if the platform allows reads and writes on
diff -ruN libjit/jit/jit-rules-arm.ins libjit-mikyt/jit/jit-rules-arm.ins
--- libjit/jit/jit-rules-arm.ins 1970-01-01 01:00:00.000000000 +0100
+++ libjit-mikyt/jit/jit-rules-arm.ins 2009-02-04 17:49:45.000000000 +0100
@@ -0,0 +1,1855 @@
+/* * jit-rules-arm.ins - Instruction selector for ARM.
+ *
+ * Copyright (C) 2004 Southern Storm Software, Pty Ltd.
+ * Copyright (C) 2008 Michele Tartara
+ *
+ * This file is part of the libjit library.
+ *
+ * The libjit library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * The libjit library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the libjit library. If not, see
+ * .
+ */
+
+%inst_type arm_inst_buf
+
+/*
+ * Register classes
+ */
+%regclass reg arm_reg
+%regclass freg32 arm_freg32
+%regclass freg64 arm_freg64
+%lregclass lreg arm_lreg
+%regclass breg arm_breg
+
+/*
+ * Conversion opcodes.
+ */
+
+JIT_OP_TRUNC_SBYTE:
+ [reg] -> {
+ arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 24);
+ arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 24);
+ }
+
+JIT_OP_TRUNC_UBYTE:
+ [reg] -> {
+ arm_alu_reg_imm8(inst, ARM_AND, $1, $1, 0xFF);
+ }
+
+JIT_OP_TRUNC_SHORT:
+ [reg] -> {
+ arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 16);
+ arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 16);
+ }
+
+JIT_OP_TRUNC_USHORT:
+ [reg] -> {
+ arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 16);
+ arm_shift_reg_imm8(inst, ARM_SHR, $1, $1, 16);
+ }
+
+JIT_OP_INT_TO_NFLOAT:
+ [=freg64, local, scratch freg32] -> {
+ //Load int from a local variable stored in memory
+ arm_load_membase_float(inst, $3, ARM_FP, $2, 0);
+ arm_convert_float_signed_integer_double(inst, $1, $3);
+}
+ [=freg64, reg, scratch freg32] -> {
+ //The int value is in a register
+ arm_mov_float_reg(inst, $3, $2);
+ arm_convert_float_signed_integer_double(inst, $1, $3)
+}
+
+JIT_OP_NFLOAT_TO_FLOAT32:
+ [=freg32, freg64] -> {
+ arm_convert_float_single_double(inst, $1, $2);
+}
+
+JIT_OP_NFLOAT_TO_FLOAT64, JIT_OP_FLOAT64_TO_NFLOAT: copy
+ [freg64] -> {
+ /* Nothing to do: float64 and nfloat are the same thing on ARM linux. Just copy the value */
+}
+
+JIT_OP_FLOAT32_TO_NFLOAT:
+ [=freg64, freg32] -> {
+ arm_convert_float_double_single(inst, $1, $2);
+}
+
+/*
+ * Arithmetic opcodes.
+ */
+
+JIT_OP_IADD:
+ [reg, immu8] -> {
+ arm_alu_reg_imm8(inst, ARM_ADD, $1, $1, $2);
+ }
+ [reg, reg] -> {
+ arm_alu_reg_reg(inst, ARM_ADD, $1, $1, $2);
+ }
+
+JIT_OP_ISUB:
+ [reg, immu8] -> {
+ arm_alu_reg_imm8(inst, ARM_SUB, $1, $1, $2);
+ }
+ [reg, reg] -> {
+ arm_alu_reg_reg(inst, ARM_SUB, $1, $1, $2);
+ }
+
+JIT_OP_IMUL:
+ [reg, immu8] -> {
+ /* Handle special cases of immediate multiplies */
+ switch($2)
+ {
+ case 0:
+ {
+ arm_mov_reg_imm8(inst, $1, 0);
+ }
+ break;
+
+ case 1: break;
+
+ case 2:
+ {
+ arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 1);
+ }
+ break;
+
+ case 4:
+ {
+ arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 2);
+ }
+ break;
+
+ case 8:
+ {
+ arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 3);
+ }
+ break;
+
+ case 16:
+ {
+ arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 4);
+ }
+ break;
+
+ case 32:
+ {
+ arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 5);
+ }
+ break;
+
+ case 64:
+ {
+ arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 6);
+ }
+ break;
+
+ case 128:
+ {
+ arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 7);
+ }
+ break;
+
+ default:
+ {
+ arm_mov_reg_imm8(inst, ARM_WORK, $2);
+ arm_mul_reg_reg(inst, $1, $1, ARM_WORK);
+ }
+ break;
+ }
+ }
+ [reg, reg] -> {
+ if($1 != $2)
+ {
+ arm_mul_reg_reg(inst, $1, $1, $2);
+ }
+ else
+ {
+ /* Cannot use the same register for both arguments */
+ arm_mov_reg_reg(inst, ARM_WORK, $2);
+ arm_mul_reg_reg(inst, $1, $1, ARM_WORK);
+ }
+ }
+
+JIT_OP_INEG:
+ [reg] -> {
+ /* -x is the same as (0 - x) */
+ arm_alu_reg_imm8(inst, ARM_RSB, $1, $1, 0);
+ }
+
+JIT_OP_LADD:
+ [lreg, lreg] -> {
+ arm_alu_cc_reg_reg(inst, ARM_ADD, $1, $1, $2);
+ arm_alu_reg_reg(inst, ARM_ADC, %1, %1, %2);
+ }
+
+JIT_OP_LSUB:
+ [lreg, lreg] -> {
+ arm_alu_cc_reg_reg(inst, ARM_SUB, $1, $1, $2);
+ arm_alu_reg_reg(inst, ARM_SBC, %1, %1, %2);
+ }
+
+JIT_OP_LNEG:
+ [lreg] -> {
+ arm_alu_reg(inst, ARM_MVN, $1, $1);
+ arm_alu_reg(inst, ARM_MVN, %1, %1);
+ arm_alu_cc_reg_imm8(inst, ARM_ADD, $1, $1, 1);
+ arm_alu_reg_imm8(inst, ARM_ADC, %1, %1, 0);
+ }
+
+JIT_OP_FADD (JIT_ARM_HAS_FLOAT_REGS):
+ [freg32, freg32] -> {
+ arm_alu_freg_freg_32(inst, ARM_FADD, $1, $1, $2);
+ }
+
+JIT_OP_FSUB (JIT_ARM_HAS_FLOAT_REGS):
+ [freg32, freg32] -> {
+ arm_alu_freg_freg_32(inst, ARM_FSUB, $1, $1, $2);
+ }
+
+JIT_OP_FMUL (JIT_ARM_HAS_FLOAT_REGS):
+ [freg32, freg32] -> {
+ arm_alu_freg_freg_32(inst, ARM_FMUL, $1, $1, $2);
+ }
+
+JIT_OP_FDIV (JIT_ARM_HAS_FLOAT_REGS):
+ [freg32, freg32] -> {
+ arm_alu_freg_freg_32(inst, ARM_FDIV, $1, $1, $2);
+ }
+
+JIT_OP_FNEG (JIT_ARM_HAS_FLOAT_REGS):
+ [freg32] -> {
+ arm_alu_freg_32(inst, ARM_MNF, $1, $1);
+ }
+
+JIT_OP_DADD, JIT_OP_NFADD (JIT_ARM_HAS_FLOAT_REGS):
+ [freg64, freg64] -> {
+ arm_alu_freg_freg(inst, ARM_FADD, $1, $1, $2);
+ }
+
+JIT_OP_DSUB, JIT_OP_NFSUB (JIT_ARM_HAS_FLOAT_REGS):
+ [freg64, freg64] -> {
+ arm_alu_freg_freg(inst, ARM_FSUB, $1, $1, $2);
+ }
+
+JIT_OP_DMUL, JIT_OP_NFMUL (JIT_ARM_HAS_FLOAT_REGS):
+ [freg64, freg64] -> {
+ arm_alu_freg_freg(inst, ARM_FMUL, $1, $1, $2);
+ }
+
+JIT_OP_DDIV, JIT_OP_NFDIV (JIT_ARM_HAS_FLOAT_REGS):
+ [freg64, freg64] -> {
+ arm_alu_freg_freg(inst, ARM_FDIV, $1, $1, $2);
+ }
+
+JIT_OP_DNEG, JIT_OP_NFNEG (JIT_ARM_HAS_FLOAT_REGS):
+ [freg64] -> {
+ arm_alu_freg(inst, ARM_MNF, $1, $1);
+ }
+
+/*
+ * Bitwise opcodes.
+ */
+
+JIT_OP_IAND:
+ [reg, immu8] -> {
+ arm_alu_reg_imm8(inst, ARM_AND, $1, $1, $2);
+ }
+ [reg, reg] -> {
+ arm_alu_reg_reg(inst, ARM_AND, $1, $1, $2);
+ }
+
+JIT_OP_IOR:
+ [reg, immu8] -> {
+ arm_alu_reg_imm8(inst, ARM_ORR, $1, $1, $2);
+ }
+ [reg, reg] -> {
+ arm_alu_reg_reg(inst, ARM_ORR, $1, $1, $2);
+ }
+
+JIT_OP_IXOR:
+ [reg, immu8] -> {
+ arm_alu_reg_imm8(inst, ARM_EOR, $1, $1, $2);
+ }
+ [reg, reg] -> {
+ arm_alu_reg_reg(inst, ARM_EOR, $1, $1, $2);
+ }
+
+JIT_OP_INOT:
+ [reg] -> {
+ /* MVN == "move not" */
+ arm_alu_reg(inst, ARM_MVN, $1, $1);
+ }
+
+JIT_OP_ISHL:
+ [reg, imm] -> {
+ arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, ($2 & 0x1F));
+ }
+ [reg, reg] -> {
+ arm_alu_reg_imm8(inst, ARM_AND, ARM_WORK, $2, 0x1F);
+ arm_shift_reg_reg(inst, ARM_SHL, $1, $1, ARM_WORK);
+ }
+
+JIT_OP_ISHR:
+ [reg, imm] -> {
+ arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, ($2 & 0x1F));
+ }
+ [reg, reg] -> {
+ arm_alu_reg_imm8(inst, ARM_AND, ARM_WORK, $2, 0x1F);
+ arm_shift_reg_reg(inst, ARM_SAR, $1, $1, ARM_WORK);
+ }
+
+JIT_OP_ISHR_UN:
+ [reg, imm] -> {
+ arm_shift_reg_imm8(inst, ARM_SHR, $1, $1, ($2 & 0x1F));
+ }
+ [reg, reg] -> {
+ arm_alu_reg_imm8(inst, ARM_AND, ARM_WORK, $2, 0x1F);
+ arm_shift_reg_reg(inst, ARM_SHR, $1, $1, ARM_WORK);
+ }
+
+JIT_OP_LAND:
+ [lreg, lreg] -> {
+ arm_alu_reg_reg(inst, ARM_AND, $1, $1, $2);
+ arm_alu_reg_reg(inst, ARM_AND, %1, %1, %2);
+ }
+
+JIT_OP_LOR:
+ [lreg, lreg] -> {
+ arm_alu_reg_reg(inst, ARM_ORR, $1, $1, $2);
+ arm_alu_reg_reg(inst, ARM_ORR, %1, %1, %2);
+ }
+
+JIT_OP_LXOR:
+ [lreg, lreg] -> {
+ arm_alu_reg_reg(inst, ARM_EOR, $1, $1, $2);
+ arm_alu_reg_reg(inst, ARM_EOR, %1, %1, %2);
+ }
+
+JIT_OP_LNOT:
+ [lreg] -> {
+ arm_alu_reg(inst, ARM_MVN, $1, $1);
+ arm_alu_reg(inst, ARM_MVN, %1, %1);
+ }
+
+/*
+ * Branch opcodes.
+ */
+
+JIT_OP_BR: branch /*spill_before*/
+ [] -> {
+ /* ARM_CC_AL == "always branch" */
+ output_branch(func, &inst, ARM_CC_AL, insn);
+
+ /* Flush the constant pool now, to minimize the probability that
+ it is accidentally flushed in the middle of a loop body */
+ jit_gen_save_inst_ptr(gen, inst);
+ flush_constants(gen, 1);
+ jit_gen_load_inst_ptr(gen, inst);
+ }
+
+JIT_OP_BR_IFALSE: branch
+ [reg] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, 0);
+ output_branch(func, &inst, ARM_CC_EQ, insn);
+ }
+
+JIT_OP_BR_ITRUE: branch
+ [reg] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, 0);
+ output_branch(func, &inst, ARM_CC_NE, insn);
+ }
+
+JIT_OP_BR_IEQ: branch
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_EQ, insn);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_EQ, insn);
+ }
+
+JIT_OP_BR_INE: branch
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_NE, insn);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_NE, insn);
+ }
+
+JIT_OP_BR_ILT: branch
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_LT, insn);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_LT, insn);
+ }
+
+JIT_OP_BR_ILT_UN: branch
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_LT_UN, insn);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_LT_UN, insn);
+ }
+
+JIT_OP_BR_ILE: branch
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_LE, insn);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_LE, insn);
+ }
+
+JIT_OP_BR_ILE_UN: branch
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_LE_UN, insn);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_LE_UN, insn);
+ }
+
+JIT_OP_BR_IGT: branch
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_GT, insn);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_GT, insn);
+ }
+
+JIT_OP_BR_IGT_UN: branch
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_GT_UN, insn);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_GT_UN, insn);
+ }
+
+JIT_OP_BR_IGE: branch
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_GE, insn);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_GE, insn);
+ }
+
+JIT_OP_BR_IGE_UN: branch
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_GE_UN, insn);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ output_branch(func, &inst, ARM_CC_GE_UN, insn);
+ }
+
+/*
+ * Comparison opcodes.
+ */
+
+JIT_OP_ICMP:
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE);
+ arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE);
+ arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT);
+ }
+
+JIT_OP_ICMP_UN:
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN);
+ arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT_UN);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN);
+ arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT_UN);
+ }
+
+JIT_OP_IEQ:
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_EQ);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_NE);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_EQ);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_NE);
+ }
+
+JIT_OP_INE:
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_NE);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_EQ);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_NE);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_EQ);
+ }
+
+JIT_OP_ILT:
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE);
+ }
+
+JIT_OP_ILT_UN:
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT_UN);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE_UN);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT_UN);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE_UN);
+ }
+
+JIT_OP_ILE:
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT);
+ }
+
+JIT_OP_ILE_UN:
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE_UN);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT_UN);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE_UN);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT_UN);
+ }
+
+JIT_OP_IGT:
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE);
+ }
+
+JIT_OP_IGT_UN:
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN);
+ }
+
+JIT_OP_IGE:
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT);
+ }
+
+JIT_OP_IGE_UN:
+ [reg, immu8] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE_UN);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT_UN);
+ }
+ [reg, reg] -> {
+ arm_test_reg_reg(inst, ARM_CMP, $1, $2);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE_UN);
+ arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT_UN);
+ }
+
+/*
+ * Pointer check opcodes.
+ */
+
+JIT_OP_CHECK_NULL: note
+ [reg] -> {
+ arm_test_reg_imm8(inst, ARM_CMP, $1, 0);
+ throw_builtin(&inst, func, ARM_CC_EQ, JIT_RESULT_NULL_REFERENCE);
+ }
+
+/*
+ * Function calls.
+ */
+
+JIT_OP_CALL:
+ [] -> {
+ jit_function_t func = (jit_function_t)(insn->dest);
+ arm_call(inst, jit_function_to_closure(func));
+ }
+
+JIT_OP_CALL_TAIL:
+ [] -> {
+ jit_function_t func = (jit_function_t)(insn->dest);
+ arm_pop_frame_tail(inst, 0);
+ arm_jump(inst, jit_function_to_closure(func));
+ }
+
+JIT_OP_CALL_INDIRECT:
+ [] -> {
+ arm_mov_reg_reg((inst), ARM_LINK, ARM_PC);
+ arm_mov_reg_reg((inst), ARM_PC, ARM_WORK);
+ }
+
+JIT_OP_CALL_VTABLE_PTR:
+ [] -> {
+ arm_mov_reg_reg((inst), ARM_LINK, ARM_PC);
+ arm_mov_reg_reg((inst), ARM_PC, ARM_WORK);
+ }
+
+JIT_OP_CALL_EXTERNAL:
+ [] -> {
+ arm_call(inst, (void *)(insn->dest));
+ }
+
+JIT_OP_RETURN:
+ [] -> {
+ jump_to_epilog(gen, &inst, block);
+ }
+
+JIT_OP_RETURN_INT: /*unary_branch*/
+ [reg] -> {
+ int cpu_reg = $1;
+ if(cpu_reg != ARM_R0)
+ {
+ arm_mov_reg_reg(inst, ARM_R0, cpu_reg);
+ }
+ jump_to_epilog(gen, &inst, block);
+ }
+
+JIT_OP_RETURN_LONG: /*unary_branch*/
+ [imm] -> {
+ mov_reg_imm(gen, &inst, ARM_R0, ((jit_int *)($1))[0]);
+ mov_reg_imm(gen, &inst, ARM_R1, ((jit_int *)($1))[1]);
+ jump_to_epilog(gen, &inst, block);
+ }
+ [local] -> {
+ arm_load_membase(inst, ARM_R0, ARM_FP, $1);
+ arm_load_membase(inst, ARM_R1, ARM_FP, $1 + 4);
+ jump_to_epilog(gen, &inst, block);
+ }
+ [lreg] -> {
+ if($1 != 0)
+ {
+ arm_mov_reg_reg(inst, ARM_R0, $1);
+ arm_mov_reg_reg(inst, ARM_R1, %1);
+ }
+ jump_to_epilog(gen, &inst, block);
+ }
+
+JIT_OP_RETURN_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): branch
+ [freg32, clobber("r0")] -> {
+ arm_mov_reg_float(inst, ARM_R0, $1);
+ jump_to_epilog(gen, &inst, block);
+ }
+
+JIT_OP_RETURN_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual
+ [] -> {
+ arm_inst_buf inst;
+ _jit_regs_spill_all(gen);
+ _jit_gen_fix_value(insn->value1);
+ jit_gen_load_inst_ptr(gen, inst);
+ if(insn->value1->is_constant)
+ {
+ mov_reg_imm
+ (gen, &inst, ARM_R0, ((int *)(insn->value1->address))[0]);
+ }
+ else
+ {
+ arm_load_membase(inst, ARM_R0, ARM_FP, insn->value1->frame_offset);
+ }
+ jump_to_epilog(gen, &inst, block);
+ jit_gen_save_inst_ptr(gen, inst);
+ }
+
+JIT_OP_RETURN_FLOAT64, JIT_OP_RETURN_NFLOAT
+ (JIT_ARM_HAS_FLOAT_REGS): branch
+ [freg64, clobber("r0", "r1")] -> {
+ arm_mov_reg_reg_double(inst,ARM_R0,ARM_R1, $1);
+ jump_to_epilog(gen, &inst, block);
+ }
+
+JIT_OP_RETURN_FLOAT64, JIT_OP_RETURN_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual
+ [] -> {
+ arm_inst_buf inst;
+ _jit_regs_spill_all(gen);
+ _jit_gen_fix_value(insn->value1);
+ jit_gen_load_inst_ptr(gen, inst);
+ if(insn->value1->is_constant)
+ {
+ mov_reg_imm
+ (gen, &inst, ARM_R0, ((int *)(insn->value1->address))[0]);
+ mov_reg_imm
+ (gen, &inst, ARM_R1, ((int *)(insn->value1->address))[1]);
+ }
+ else
+ {
+ arm_load_membase(inst, ARM_R0, ARM_FP, insn->value1->frame_offset);
+ arm_load_membase(inst, ARM_R1, ARM_FP,
+ insn->value1->frame_offset + 4);
+ }
+ jump_to_epilog(gen, &inst, block);
+ jit_gen_save_inst_ptr(gen, inst);
+ }
+
+JIT_OP_RETURN_SMALL_STRUCT: note
+ [reg, imm, clobber("r0", "r1")] -> {
+ //$1: address of the struct to be returned
+ //$2: size of the struct to be returned
+
+ //Prevent the accidental overwriting of the address
+ int temp_reg = $1;
+ if(temp_reg < 3)
+ {
+ arm_mov_reg_reg(inst, ARM_WORK, temp_reg);
+ temp_reg = ARM_WORK;
+ }
+
+ //Copy the struct to the return register in a way that's appropriate to its size
+ switch($2)
+ {
+ case 1:
+ arm_load_membase_byte(inst, ARM_R0, temp_reg, 0);
+ break;
+
+ case 2:
+ arm_load_membase_ushort(inst, ARM_R0, temp_reg, 0);
+ break;
+
+ case 3:
+ arm_load_membase_ushort(inst, ARM_R0, temp_reg, 0);
+ arm_load_membase_byte(inst, ARM_R1, temp_reg, 2);
+ arm_shift_reg_imm8(inst, ARM_SHL, ARM_R1, ARM_R1, 16);
+ arm_alu_reg_reg(inst, ARM_ORR, ARM_R0, ARM_R0, ARM_R1);
+ break;
+
+ case 4:
+ arm_load_membase(inst, ARM_R0, temp_reg, 0);
+ break;
+
+ /*TODO: is this the right way to return a struct > 4 bytes?
+ * Or should it be returned by address? Look at the Procedure Call Standard!
+ */
+
+ case 5:
+ arm_load_membase(inst, ARM_R0, temp_reg, 0);
+ arm_load_membase_byte(inst, ARM_R1, temp_reg, 4);
+ break;
+
+ case 6:
+ arm_load_membase(inst, ARM_R0, temp_reg, 0);
+ arm_load_membase_ushort(inst, ARM_R1, temp_reg, 4);
+ break;
+
+ case 7:
+ arm_load_membase(inst, ARM_R0, temp_reg, 0);
+ arm_load_membase_ushort(inst, ARM_R1, temp_reg, 4);
+ arm_load_membase_byte(inst, ARM_R2, temp_reg, 6);
+ arm_shift_reg_imm8(inst, ARM_SHL, ARM_R2, ARM_R2, 16);
+ arm_alu_reg_reg(inst, ARM_ORR, ARM_R1, ARM_R1, ARM_R2);
+ break;
+
+ case 8:
+ arm_load_membase(inst, ARM_R0, temp_reg, 0);
+ arm_load_membase(inst, ARM_R1, temp_reg, 4);
+ break;
+ }
+
+ jump_to_epilog(gen, &inst, block);
+ }
+
+JIT_OP_SETUP_FOR_NESTED: /*spill_before*/
+ [] -> {
+ jit_nint nest_reg = jit_value_get_nint_constant(insn->value1);
+ if(nest_reg == -1)
+ {
+ arm_push_reg(inst, ARM_FP);
+ }
+ else
+ {
+ arm_mov_reg_reg(inst, _jit_reg_info[nest_reg].cpu_reg, ARM_FP);
+ }
+ }
+
+JIT_OP_SETUP_FOR_SIBLING: /*spill_before*/
+ [] -> {
+ jit_nint level = jit_value_get_nint_constant(insn->value1);
+ jit_nint nest_reg = jit_value_get_nint_constant(insn->value2);
+ int cpu_reg;
+ if(nest_reg == -1)
+ {
+ cpu_reg = ARM_R0;
+ }
+ else
+ {
+ cpu_reg = _jit_reg_info[nest_reg].cpu_reg;
+ }
+ arm_load_membase(inst, cpu_reg, ARM_FP, JIT_APPLY_PARENT_FRAME_OFFSET);
+ while(level > 0)
+ {
+ arm_load_membase(inst, cpu_reg, cpu_reg,
+ JIT_APPLY_PARENT_FRAME_OFFSET);
+ --level;
+ }
+ if(nest_reg == -1)
+ {
+ arm_push_reg(inst, cpu_reg);
+ }
+ }
+
+JIT_OP_IMPORT:
+ [] -> {
+ /* TODO */
+ TODO();
+ }
+
+/*
+ * Exception handling
+ */
+JIT_OP_THROW: branch
+ [reg] -> {
+
+ arm_push_reg(inst, $1);
+ if(func->builder->setjmp_value != 0)
+ {
+ /* We have a "setjmp" block in the current function,
+ so we must record the location of the throw first */
+ jit_nint pc_offset;
+
+ _jit_gen_fix_value(func->builder->setjmp_value);
+
+ pc_offset = func->builder->setjmp_value->frame_offset +
+ jit_jmp_catch_pc_offset;
+
+ if(func->builder->position_independent)
+ {
+ arm_call_imm(inst, 0);
+ arm_pop_membase(inst, ARM_FP, pc_offset);
+ }
+ else
+ {
+ int pc = (int) (unsigned char *) arm_inst_get_posn(inst);
+ arm_mov_membase_imm(inst, ARM_FP, pc_offset, pc, 4, ARM_WORK);
+ }
+ }
+ arm_call(inst, (void *)jit_exception_throw);
+ }
+
+JIT_OP_LOAD_PC:
+[=reg] -> {
+ if(func->builder->position_independent)
+ {
+ arm_call_imm(inst, 0);
+ arm_pop_reg(inst, $1);
+ }
+ else
+ {
+ int pc = inst.current;
+ mov_reg_imm(gen, &inst, $1, pc);
+ }
+}
+
+JIT_OP_ENTER_FINALLY:
+[] -> { /*
+ * The return address is in the link register
+ * We must save it on the stack in case it will be overwritten by the content
+ * of the "finally" block.
+ * In order to respect the ABI of the ARM architecture, that prescribes an 8-byte
+ * alignment for the stack at a public interface, we save the value twice,
+ * in order to move the current SP by 8 bytes
+ * (we could have just saved the value once and then moved the SP by 4 bytes)
+ */
+ arm_push_reg(inst, ARM_LINK);
+ arm_push_reg(inst, ARM_LINK);
+}
+
+JIT_OP_LEAVE_FINALLY: branch
+[] -> {
+ /* The "finally" return address is on the stack (twice, just for padding)*/
+ arm_pop_reg(inst, ARM_LINK);
+ arm_pop_reg(inst, ARM_LINK);
+ arm_return(inst);
+}
+
+JIT_OP_CALL_FINALLY: branch
+[] -> {
+ jit_block_t block;
+ int offset;
+ block = jit_block_from_label(func, (jit_label_t)(insn->dest));
+ if(!block)
+ {
+ return;
+ }
+ if(arm_inst_get_posn(inst) >= arm_inst_get_limit(inst))
+ {
+ /* The buffer has overflowed, so don't worry about fixups */
+ return;
+ }
+ if(block->address)
+ {
+ /* We already know the address of the block */
+ arm_call(inst, block->address);
+ }
+ else
+ {
+ /* Output a placeholder and record on the block's fixup list */
+ if(block->fixup_list)
+ {
+ offset = (int)(((unsigned char *)arm_inst_get_posn(inst)) -
+ ((unsigned char *)(block->fixup_list)));
+ }
+ else
+ {
+ offset = 0;
+ }
+ arm_call_imm(inst, offset);
+ block->fixup_list = (void *)(arm_inst_get_posn(inst) - 1);
+ }
+}
+
+JIT_OP_ADDRESS_OF_LABEL:
+[=reg] -> {
+ block = jit_block_from_label(func, (jit_label_t)(insn->value1));
+ if(func->builder->position_independent)
+ {
+ /* TODO */
+ TODO();
+ }
+ else
+ {
+ if(block->address)
+ {
+ mov_reg_imm(gen, &inst, $1, block->address);
+ }
+ else
+ {
+ /* Output a placeholder and record on the block's fixup list */
+ mov_reg_imm(gen, &inst, $1, (int)(block->fixup_absolute_list));
+ block->fixup_absolute_list = (void *)(inst.current - 1);
+ }
+ }
+}
+
+/*
+ * Data manipulation.
+ */
+
+JIT_OP_COPY_LOAD_SBYTE:
+ [reg] -> {}
+
+JIT_OP_COPY_LOAD_UBYTE:
+ [reg] -> {}
+
+JIT_OP_COPY_LOAD_SHORT:
+ [reg] -> {}
+
+JIT_OP_COPY_LOAD_USHORT:
+ [reg] -> {}
+
+JIT_OP_COPY_INT: copy
+ [=local, imm, scratch reg] -> {
+ arm_mov_membase_imm(inst, ARM_FP, $1, $2, 4, $3);
+ }
+ [reg] -> {}
+
+
+JIT_OP_COPY_LONG: copy
+ [lreg] -> {}
+
+JIT_OP_COPY_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): copy
+ [freg32] -> {}
+
+JIT_OP_COPY_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual
+ [] -> {
+ arm_inst_buf inst;
+ _jit_regs_force_out(gen, insn->value1, 0);
+ _jit_regs_force_out(gen, insn->dest, 1);
+ _jit_gen_fix_value(insn->value1);
+ _jit_gen_fix_value(insn->dest);
+ jit_gen_load_inst_ptr(gen, inst);
+ if(insn->value1->is_constant)
+ {
+ mov_reg_imm
+ (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
+ }
+ else
+ {
+ arm_load_membase(inst, ARM_WORK, ARM_FP,
+ insn->value1->frame_offset);
+ }
+ arm_store_membase(inst, ARM_WORK, ARM_FP, insn->dest->frame_offset);
+ jit_gen_save_inst_ptr(gen, inst);
+ }
+
+JIT_OP_COPY_FLOAT64, JIT_OP_COPY_NFLOAT (JIT_ARM_HAS_FLOAT_REGS): copy
+ [freg64] -> {}
+
+JIT_OP_COPY_FLOAT64, JIT_OP_COPY_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual
+ [] -> {
+ arm_inst_buf inst;
+ _jit_regs_force_out(gen, insn->value1, 0);
+ _jit_regs_force_out(gen, insn->dest, 1);
+ _jit_gen_fix_value(insn->value1);
+ _jit_gen_fix_value(insn->dest);
+ jit_gen_load_inst_ptr(gen, inst);
+ if(insn->value1->is_constant)
+ {
+ mov_reg_imm
+ (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
+ arm_store_membase(inst, ARM_WORK, ARM_FP,
+ insn->dest->frame_offset);
+ mov_reg_imm
+ (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
+ arm_store_membase(inst, ARM_WORK, ARM_FP,
+ insn->dest->frame_offset + 4);
+ }
+ else
+ {
+ arm_load_membase(inst, ARM_WORK, ARM_FP,
+ insn->value1->frame_offset);
+ arm_store_membase(inst, ARM_WORK, ARM_FP,
+ insn->dest->frame_offset);
+ arm_load_membase(inst, ARM_WORK, ARM_FP,
+ insn->value1->frame_offset + 4);
+ arm_store_membase(inst, ARM_WORK, ARM_FP,
+ insn->dest->frame_offset + 4);
+ }
+ jit_gen_save_inst_ptr(gen, inst);
+ }
+
+JIT_OP_COPY_STRUCT:
+ [=frame, frame, scratch reg] -> {
+ inst = memory_copy(gen, inst, ARM_FP, $1, ARM_FP, $2,
+ jit_type_get_size(jit_value_get_type(insn->dest)), $3);
+ }
+
+JIT_OP_COPY_STORE_BYTE: manual
+ [] -> {
+ arm_inst_buf inst;
+ int reg;
+ _jit_regs_force_out(gen, insn->dest, 1);
+ _jit_gen_fix_value(insn->dest);
+ reg = _jit_regs_load_value
+ (gen, insn->value1, 0,
+ (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
+ JIT_INSN_VALUE1_LIVE)));
+ jit_gen_load_inst_ptr(gen, inst);
+ arm_store_membase_byte(inst, _jit_reg_info[reg].cpu_reg,
+ ARM_FP, insn->dest->frame_offset);
+ jit_gen_save_inst_ptr(gen, inst);
+ }
+
+JIT_OP_COPY_STORE_SHORT: manual
+ [] -> {
+ arm_inst_buf inst;
+ int reg;
+ _jit_regs_force_out(gen, insn->dest, 1);
+ _jit_gen_fix_value(insn->dest);
+ reg = _jit_regs_load_value
+ (gen, insn->value1, 1,
+ (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
+ JIT_INSN_VALUE1_LIVE)));
+ jit_gen_load_inst_ptr(gen, inst);
+ arm_store_membase_short(inst, _jit_reg_info[reg].cpu_reg,
+ ARM_FP, insn->dest->frame_offset);
+ jit_gen_save_inst_ptr(gen, inst);
+ //_jit_regs_free_reg(gen, reg, 1); //TODO: check if it's needed
+ }
+
+JIT_OP_ADDRESS_OF:
+ [=reg, frame] -> {
+ if($2 > 0)
+ {
+ arm_alu_reg_imm(inst, ARM_ADD, $1, ARM_FP, $2);
+ }
+ else if($2 < 0)
+ {
+ arm_alu_reg_imm(inst, ARM_SUB, $1, ARM_FP, -$2);
+ }
+ else
+ {
+ arm_mov_reg_reg(inst, $1, ARM_FP);
+ }
+
+ }
+
+/*
+ * Stack pushes and pops.
+ */
+
+JIT_OP_INCOMING_REG, JIT_OP_RETURN_REG: note
+ [reg] -> {
+ /*
+ * This rule does nothing itself. Also at this point
+ * the value is supposed to be already in the register
+ * so the "reg" pattern does not load it either. But
+ * it allows the allocator to check the liveness flags
+ * and free the register if the value is dead.
+ */
+ }
+
+JIT_OP_PUSH_INT: note
+ [reg] -> {
+ arm_push_reg(inst, $1);
+ }
+
+JIT_OP_PUSH_LONG: note
+ [lreg] -> {
+ arm_push_reg(inst, %1);
+ arm_push_reg(inst, $1);
+ gen->stack_changed=1;
+ }
+
+JIT_OP_PUSH_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): note
+ [freg32] -> {
+ arm_push_reg_float32(inst, $1);
+ }
+
+JIT_OP_PUSH_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual
+ [] -> {
+ arm_inst_buf inst;
+ _jit_regs_force_out(gen, insn->value1, 0);
+ _jit_gen_fix_value(insn->value1);
+ jit_gen_load_inst_ptr(gen, inst);
+ if(insn->value1->is_constant)
+ {
+ mov_reg_imm
+ (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
+ }
+ else
+ {
+ arm_load_membase(inst, ARM_WORK, ARM_FP,
+ insn->value1->frame_offset);
+ }
+ arm_push_reg(inst, ARM_WORK);
+ jit_gen_save_inst_ptr(gen, inst);
+ }
+
+JIT_OP_PUSH_FLOAT64, JIT_OP_PUSH_NFLOAT (JIT_ARM_HAS_FLOAT_REGS): note
+ [freg64] -> {
+ arm_push_reg_float64(inst, $1);
+ }
+
+JIT_OP_PUSH_FLOAT64, JIT_OP_PUSH_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual
+ [] -> {
+ arm_inst_buf inst;
+ _jit_regs_force_out(gen, insn->value1, 0);
+ _jit_gen_fix_value(insn->value1);
+ jit_gen_load_inst_ptr(gen, inst);
+ if(insn->value1->is_constant)
+ {
+ mov_reg_imm
+ (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
+ arm_push_reg(inst, ARM_WORK);
+ mov_reg_imm
+ (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
+ arm_push_reg(inst, ARM_WORK);
+ }
+ else
+ {
+ arm_load_membase(inst, ARM_WORK, ARM_FP,
+ insn->value1->frame_offset + 4);
+ arm_push_reg(inst, ARM_WORK);
+ arm_load_membase(inst, ARM_WORK, ARM_FP,
+ insn->value1->frame_offset);
+ arm_push_reg(inst, ARM_WORK);
+ }
+ jit_gen_save_inst_ptr(gen, inst);
+ }
+
+JIT_OP_PUSH_STRUCT: /*unary_note*/
+ [reg] -> {
+ /* TODO */
+ TODO();
+ }
+
+JIT_OP_POP_STACK:
+ [] -> {
+ arm_alu_reg_imm(inst, ARM_ADD, ARM_SP, ARM_SP, insn->value1->address);
+ }
+
+JIT_OP_FLUSH_SMALL_STRUCT:
+ [] -> {
+ jit_nuint size;
+ jit_nint offset;
+ _jit_gen_fix_value(insn->value1);
+ size = jit_type_get_size(jit_value_get_type(insn->value1));
+ offset = insn->value1->frame_offset;
+ switch(size)
+ {
+ case 1:
+ {
+ arm_store_membase_byte(inst, ARM_R0, ARM_FP, offset);
+ }
+ break;
+
+ case 2:
+ {
+ arm_store_membase_short(inst, ARM_R0, ARM_FP, offset);
+ }
+ break;
+
+ case 3:
+ {
+ arm_mov_reg_reg(inst, ARM_R1, ARM_R0);
+ arm_store_membase_short(inst, ARM_R0, ARM_FP, offset);
+ arm_shift_reg_imm8(inst, ARM_SHR, ARM_R0, ARM_R1, 16);
+ arm_store_membase_byte(inst, ARM_R0, ARM_FP, offset + 2);
+ }
+ break;
+
+ case 4:
+ {
+ arm_store_membase(inst, ARM_R0, ARM_FP, offset);
+ }
+ break;
+
+ case 5:
+ {
+ arm_store_membase(inst, ARM_R0, ARM_FP, offset);
+ arm_store_membase_byte(inst, ARM_R1, ARM_FP, offset + 4);
+ }
+ break;
+
+ case 6:
+ {
+ arm_store_membase(inst, ARM_R0, ARM_FP, offset);
+ arm_store_membase_short(inst, ARM_R1, ARM_FP, offset + 4);
+ }
+ break;
+
+ case 7:
+ {
+ arm_store_membase(inst, ARM_R0, ARM_FP, offset);
+ arm_mov_reg_reg(inst, ARM_R2, ARM_R1);
+ arm_store_membase_short(inst, ARM_R1, ARM_FP, offset + 4);
+ arm_shift_reg_imm8(inst, ARM_SHR, ARM_R1, ARM_R2, 16);
+ arm_store_membase_byte(inst, ARM_R1, ARM_FP, offset + 6);
+ }
+ break;
+
+ case 8:
+ {
+ arm_store_membase(inst, ARM_R0, ARM_FP, offset);
+ arm_store_membase(inst, ARM_R1, ARM_FP, offset + 4);
+ }
+ break;
+ }
+ }
+
+JIT_OP_SET_PARAM_INT: note
+ [imm, imm] -> {
+ arm_mov_membase_imm(inst, ARM_SP, $2, $1, 4, ARM_WORK);
+ }
+ [reg, imm] -> {
+ arm_mov_membase_reg(inst, ARM_SP, $2, $1, 4);
+ }
+
+JIT_OP_SET_PARAM_LONG: /*unary_note*/
+ [lreg] -> {
+ arm_store_membase(inst, $1, ARM_SP, insn->value2->address);
+ arm_store_membase(inst, %1, ARM_SP, insn->value2->address + 4);
+ }
+
+JIT_OP_SET_PARAM_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): /*unary_note*/
+ [freg32] -> {
+ arm_store_membase_float32(inst, $1, ARM_SP, insn->value2->address);
+ }
+
+JIT_OP_SET_PARAM_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual
+ [] -> {
+ arm_inst_buf inst;
+ _jit_regs_force_out(gen, insn->value1, 0);
+ _jit_gen_fix_value(insn->value1);
+ jit_gen_load_inst_ptr(gen, inst);
+ if(insn->value1->is_constant)
+ {
+ mov_reg_imm
+ (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
+ arm_store_membase
+ (inst, ARM_WORK, ARM_SP, insn->value2->address);
+ }
+ else
+ {
+ arm_load_membase(inst, ARM_WORK, ARM_FP,
+ insn->value1->frame_offset);
+ arm_store_membase
+ (inst, ARM_WORK, ARM_SP, insn->value2->address);
+ }
+ jit_gen_save_inst_ptr(gen, inst);
+ }
+
+JIT_OP_SET_PARAM_FLOAT64, JIT_OP_SET_PARAM_NFLOAT
+ (JIT_ARM_HAS_FLOAT_REGS): /*unary_note*/
+ [freg64] -> {
+ arm_store_membase_float64(inst, $1, ARM_SP, insn->value2->address);
+ }
+
+JIT_OP_SET_PARAM_FLOAT64, JIT_OP_SET_PARAM_NFLOAT
+ (!JIT_ARM_HAS_FLOAT_REGS): manual
+ [] -> {
+ arm_inst_buf inst;
+ _jit_regs_force_out(gen, insn->value1, 0);
+ _jit_gen_fix_value(insn->value1);
+ jit_gen_load_inst_ptr(gen, inst);
+ if(insn->value1->is_constant)
+ {
+ mov_reg_imm
+ (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
+ arm_store_membase
+ (inst, ARM_WORK, ARM_SP, insn->value2->address);
+ mov_reg_imm
+ (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
+ arm_store_membase
+ (inst, ARM_WORK, ARM_SP, insn->value2->address + 4);
+ }
+ else
+ {
+ arm_load_membase(inst, ARM_WORK, ARM_FP,
+ insn->value1->frame_offset);
+ arm_store_membase
+ (inst, ARM_WORK, ARM_SP, insn->value2->address);
+ arm_load_membase(inst, ARM_WORK, ARM_FP,
+ insn->value1->frame_offset + 4);
+ arm_store_membase
+ (inst, ARM_WORK, ARM_SP, insn->value2->address + 4);
+ }
+ jit_gen_save_inst_ptr(gen, inst);
+ }
+
+JIT_OP_SET_PARAM_STRUCT: note
+[reg, imm, scratch reg] -> {
+ /* Handle arbitrary-sized structures */
+ jit_nint offset = jit_value_get_nint_constant(insn->dest);
+ inst = memory_copy(gen, inst, ARM_SP, offset, $1, 0, $2, $3);
+}
+
+/*
+ * Pointer-relative loads and stores.
+ */
+JIT_OP_LOAD_RELATIVE_SBYTE:
+ [reg] -> {
+ arm_load_membase_sbyte(inst, $1, $1, insn->value2->address);
+ }
+
+JIT_OP_LOAD_RELATIVE_UBYTE:
+ [reg] -> {
+ arm_load_membase_byte(inst, $1, $1, insn->value2->address);
+ }
+
+JIT_OP_LOAD_RELATIVE_SHORT:
+ [reg] -> {
+ arm_load_membase_short(inst, $1, $1, insn->value2->address);
+ }
+
+JIT_OP_LOAD_RELATIVE_USHORT:
+ [reg] -> {
+ arm_load_membase_ushort(inst, $1, $1, insn->value2->address);
+ }
+
+JIT_OP_LOAD_RELATIVE_INT:
+ [reg] -> {
+ arm_load_membase(inst, $1, $1, insn->value2->address);
+ }
+
+JIT_OP_LOAD_RELATIVE_LONG:
+ [=lreg, reg, imm] -> {
+ if($1 == $2)
+ {
+ arm_mov_reg_membase(inst, %1, $2, $3 + 4, 4);
+ arm_mov_reg_membase(inst, $1, $2, $3, 4);
+ }
+ else
+ {
+ arm_mov_reg_membase(inst, $1, $2, $3, 4);
+ arm_mov_reg_membase(inst, %1, $2, $3 + 4, 4);
+ }
+ }
+
+JIT_OP_LOAD_RELATIVE_FLOAT32:
+[=freg32, reg, imm] -> {
+ arm_fld_membase(inst, $1, $2, $3, 0);
+}
+
+JIT_OP_LOAD_RELATIVE_FLOAT64:
+[=freg64, reg, imm] -> {
+ arm_fld_membase(inst, $1, $2, $3, 1);
+}
+
+JIT_OP_LOAD_RELATIVE_NFLOAT: manual
+ [] -> {
+ /* TODO */
+ TODO();
+ abort();
+ }
+
+JIT_OP_LOAD_RELATIVE_STRUCT: more_space
+[=frame, reg, imm, scratch reg] -> {
+ inst = memory_copy(gen, inst, ARM_FP, $1, $2, $3, jit_type_get_size(jit_value_get_type(insn->dest)), $4);
+}
+
+JIT_OP_STORE_RELATIVE_BYTE: ternary
+[imm, imm, imm, scratch reg] -> {
+ arm_mov_mem_imm(inst, $1 + $3, $2, 1, $4);
+}
+[imm, breg, imm] -> {
+ arm_mov_mem_reg(inst, $1 + $3, $2, 1);
+}
+[reg, imm, imm] -> {
+ arm_mov_membase_imm(inst, $1, $3, $2, 1, ARM_WORK);
+}
+[reg, breg, imm] -> {
+ arm_mov_membase_reg(inst, $1, $3, $2, 1);
+}
+
+JIT_OP_STORE_RELATIVE_SHORT: ternary
+[imm, imm, imm, scratch reg] -> {
+ arm_mov_mem_imm(inst, $1 + $3, $2, 2, $4);
+}
+[imm, reg, imm] -> {
+ arm_mov_mem_reg(inst, $1 + $3, $2, 2);
+}
+[reg, imm, imm] -> {
+ arm_mov_membase_imm(inst, $1, $3, $2, 2, ARM_WORK);
+}
+[reg, reg, imm] -> {
+ arm_mov_membase_reg(inst, $1, $3, $2, 2);
+}
+
+JIT_OP_STORE_RELATIVE_INT: ternary
+ [imm, imm, imm, scratch reg] -> {
+ arm_mov_mem_imm(inst, $1 + $3, $2, 4, $4);
+ }
+ [imm, reg, imm] -> {
+ arm_mov_mem_reg(inst, $1 + $3, $2, 4);
+ }
+ [reg, imm, imm] -> {
+ arm_mov_membase_imm(inst, $1, $3, $2, 4, ARM_WORK);
+ }
+ [reg, reg, imm] -> {
+ arm_mov_membase_reg(inst, $1, $3, $2, 4);
+ }
+
+JIT_OP_STORE_RELATIVE_LONG: ternary
+ [reg, imm, imm] -> {
+ arm_mov_membase_imm(inst, $1, $3, *(int *)($2), 4, ARM_WORK);
+ arm_mov_membase_imm(inst, $1, $3 + 4, *(int *)($2 + 4), 4, ARM_WORK);
+ }
+ [reg, local, imm, scratch reg] -> {
+ arm_mov_reg_membase(inst, $4, ARM_FP, $2, 4);
+ arm_mov_membase_reg(inst, $1, $3, $4, 4);
+ arm_mov_reg_membase(inst, $4, ARM_FP, $2 + 4, 4);
+ arm_mov_membase_reg(inst, $1, $3 + 4, $4, 4);
+ }
+ [reg, lreg, imm] -> {
+ arm_mov_membase_reg(inst, $1, $3, $2, 4);
+ arm_mov_membase_reg(inst, $1, $3 + 4, %2, 4);
+ }
+
+JIT_OP_STORE_RELATIVE_FLOAT32: ternary
+ [reg, imm, imm] -> {
+ arm_mov_membase_imm(inst, $1, $3, ((int *)($2))[0], 4, ARM_WORK);
+ }
+ [reg, freg32, imm] -> {
+ arm_store_membase_float32(inst, $2, $1, $3);
+ }
+
+JIT_OP_STORE_RELATIVE_FLOAT64: ternary
+ [reg, imm, imm, scratch reg] -> {
+ arm_mov_membase_imm(inst, $1, $3, ((int *)($2))[0], 4, $4);
+ arm_mov_membase_imm(inst, $1, $3 + 4, ((int *)($2))[1], 4, $4);
+ }
+ [reg, freg64, imm] -> {
+ arm_store_membase_float64(inst, $2, $1, $3);
+ }
+
+JIT_OP_STORE_RELATIVE_NFLOAT: manual
+ [] -> {
+ /* TODO */
+ TODO();
+ abort();
+ }
+
+JIT_OP_STORE_RELATIVE_STRUCT: manual
+[] -> {
+ arm_inst_buf inst;
+ int reg = _jit_regs_load_value(gen, insn->dest, 0,
+ (insn->flags & (JIT_INSN_DEST_NEXT_USE |
+ JIT_INSN_DEST_LIVE)));
+ _jit_regs_spill_all(gen);
+ _jit_gen_fix_value(insn->value1);
+ jit_gen_load_inst_ptr(gen, inst);
+ if(!jit_cache_check_for_n(&(gen->posn), 128))
+ {
+ jit_cache_mark_full(&(gen->posn));
+ return;
+ }
+ reg = _jit_reg_info[reg].cpu_reg;
+ inst = memory_copy(gen, inst, reg, (int)(insn->value2->address),
+ ARM_FP, insn->value1->frame_offset,
+ jit_type_get_size(jit_value_get_type(insn->value1)), -1);
+ jit_gen_save_inst_ptr(gen, inst);
+}
+
+JIT_OP_ADD_RELATIVE:
+ [reg] -> {
+ if(insn->value2->address != 0)
+ {
+ arm_alu_reg_imm(inst, ARM_ADD, $1, $1, insn->value2->address);
+ }
+ }
+
+/*
+* Array element loads and stores.
+*/
+JIT_OP_LOAD_ELEMENT_UBYTE:
+[=reg, reg, reg] -> {
+ arm_widen_memindex(inst, $1, $2, 0, $3, 0, 0, 0);
+}
+
+JIT_OP_LOAD_ELEMENT_USHORT:
+[=reg, reg, reg] -> {
+ arm_widen_memindex(inst, $1, $2, 0, $3, 1, 0, 1);
+}
+
+JIT_OP_LOAD_ELEMENT_INT:
+[=reg, reg, reg] -> {
+ /* The last parameter is unimportant: it's not used,
+ since the displacement (4th param) is 0 */
+ arm_mov_reg_memindex(inst, $1, $2, 0, $3, 2, 4, 0);
+}
+
+JIT_OP_LOAD_ELEMENT_LONG:
+[=lreg, reg, reg, scratch reg, scratch reg] -> {
+ //$1=destination long register (1-st word, LSB)
+ //%1=destination long register (2-nd word, MSB)
+ //$2=base register
+ //$3=index register
+ //$4=scratch register for arm_mov_reg_memindex
+ //$5=scratch register for overwriting prevention
+
+ assert($2 != $3);
+
+ int basereg=$2;
+ int indexreg=$3;
+
+ //Write the 1-st word
+ if($1 == basereg)
+ {
+ //Prevent base reg from being overwritten
+ arm_mov_reg_reg(inst, $5, basereg);
+ basereg=$5;
+ }
+ else if ($1 == indexreg)
+ {
+ //Prevent index reg from being overwritten
+ arm_mov_reg_reg(inst, $5, indexreg);
+ indexreg=$5;
+ }
+ arm_mov_reg_memindex(inst, $1, basereg, 0, indexreg, 3, 4, $4);
+
+ //Write the 2-nd word
+ arm_mov_reg_memindex(inst, %1, basereg, 4, indexreg, 3, 4, $4);
+}
+
+JIT_OP_LOAD_ELEMENT_FLOAT64:
+[=freg64, reg, reg, scratch reg] -> {
+ arm_fld_memindex(inst, $1, $2, 0, $3, 3, 1, $4);
+}
+
+JIT_OP_STORE_ELEMENT_BYTE: ternary
+[reg, reg, breg, scratch reg] -> {
+ arm_mov_memindex_reg(inst, $1, 0, $2, 0, $3, 1, $4);
+}
+
+JIT_OP_STORE_ELEMENT_SHORT: ternary
+[reg, reg, reg, scratch reg] -> {
+ arm_mov_memindex_reg(inst, $1, 0, $2, 1, $3, 2, $4);
+}
+
+JIT_OP_STORE_ELEMENT_INT: ternary
+[reg, reg, reg, scratch reg] -> {
+ arm_mov_memindex_reg(inst, $1, 0, $2, 2, $3, 4, $4);
+}
+
+JIT_OP_STORE_ELEMENT_FLOAT64: ternary
+[reg, reg, freg64, scratch reg] -> {
+ arm_fst_memindex(inst, $3, $1, 0, $2, 3, 1, $4);
+}
+
+/*
+* Allocate memory from the stack.
+*/
+JIT_OP_ALLOCA:
+[reg] -> {
+ //The ARM stack must always be 4-byte aligned and must be 8-byte aligned at a public interface.
+ //Since we don't know when this function will be called, let's align to 8 bytes.
+ arm_alu_reg_imm(inst, ARM_ADD, $1, $1, 7);
+ arm_alu_reg_imm(inst, ARM_AND, $1, $1, ~7);
+ arm_alu_reg_reg(inst, ARM_SUB, ARM_SP, ARM_SP, $1);
+ arm_mov_reg_reg(inst, $1, ARM_SP);
+ gen->stack_changed = 1;
+}
+
+/*
+ * Block operations
+ */
+JIT_OP_MEMCPY: ternary
+ [any, any, imm, if("$3 <= 0")] -> { }
+ [reg, reg, imm, scratch reg, clobber("r0", "r1", "r2")] ->
+ {
+ /*
+ * Call jit_memcpy(dest,src,size).
+ * $1=dest, $2=src, $3=size
+ */
+ int dest=$1;
+ int src=$2;
+
+ if (dest != ARM_R0) {
+ if(src==ARM_R0)
+ {
+ //Prevent overwriting useful data
+ arm_mov_reg_reg(inst, $4, src);
+ src=$4;
+ }
+ arm_mov_reg_reg((inst), ARM_R0, dest);
+ }
+ if (src != ARM_R1) {
+ //Move the "src" from wherever it is to where it should be
+ arm_mov_reg_reg(inst, ARM_R1, src);
+ }
+ mov_reg_imm(gen, &(inst), ARM_R2, $3);
+
+ //Call the function
+ arm_call(inst, jit_memcpy);
+ }
+ [reg, reg, reg, scratch breg, clobber("r0", "r1", "r2")] -> {
+ /*
+ * Call jit_memcpy(dest,src,size).
+ * $1=dest, $2=src, $3=size
+ */
+ if ($1 != ARM_R0) {
+ if($2==ARM_R0)
+ {
+ //Prevent overwriting useful data
+ arm_mov_reg_reg(inst, $4, $2);
+ }
+ arm_mov_reg_reg((inst), ARM_R0, $1);
+ }
+ if ($2 != ARM_R1) {
+ if ($2==ARM_R0)
+ {
+ //Recover previously saved data
+ arm_mov_reg_reg(inst, ARM_R1, $4);
+ }
+ else
+ {
+ arm_mov_reg_reg((inst), ARM_R1, $2);
+ }
+ }
+ if ($3 != ARM_R2) {
+ arm_mov_reg_reg((inst), ARM_R2, $3);
+ }
+
+ //Call the function
+ arm_call(inst, jit_memcpy);
+
+ }
+
+JIT_OP_MEMSET: ternary
+[any, any, imm, if("$3 <= 0")] -> { }
+[reg, imm, imm, if("$3 <= 32"), space("32 + $3 * 4")] -> {
+ // $1 = pointer to the initial memory location
+ // $2 = value to be written in memory
+ // $3 = length in bytes
+ int disp;
+ disp = 0;
+ while($3 >= (disp + 4))
+ {
+ //NB: if 0= (disp + 2))
+ {
+ arm_mov_membase_imm(inst, $1, disp, $2 * 0x0101, 2, ARM_WORK);
+ disp += 2;
+ }
+ if(insn->value2->address > disp)
+ {
+ arm_mov_membase_imm(inst, $1, disp, $2, 1, ARM_WORK);
+ }
+}
+[reg, breg, imm, if("$3 < 4")] -> {
+ TODO();
+ abort();
+}
+[reg, +reg, imm, scratch reg, if("$3 <= 32 && ($3 % 2) == 0"), space("32 + $3 * 4")] -> {
+ // $1 = pointer to the initial memory location
+ // $2 = value to be written in memory
+ // $3 = length in bytes
+ // $4 = scratch register
+ int disp;
+ arm_mov_reg_reg(inst, $4, $2);
+ arm_shift_reg_imm8(inst, ARM_SHL, $2, $2, 8);
+ arm_alu_reg_reg(inst, ARM_ORR, $2, $2, $4);
+ arm_mov_reg_reg(inst, $4, $2);
+ arm_shift_reg_imm8(inst, ARM_SHL, $2, $2, 16);
+ arm_alu_reg_reg(inst, ARM_ORR, $2, $2, $4);
+ disp = 0;
+ while($3 >= (disp + 4))
+ {
+ arm_mov_membase_reg(inst, $1, disp, $2, 4);
+ disp += 4;
+ }
+ if($3 > disp)
+ {
+ arm_mov_membase_reg(inst, $1, disp, $2, 2);
+ }
+}
+[reg, +breg, imm, scratch reg,
+if("$3 <= 32 && ($3 % 2) != 0"), space("32 + $3 * 4")] -> {
+ TODO();
+ abort();
+}
+[reg, reg, reg, clobber("r0", "r1", "r2"), scratch reg] -> {
+ // $1 = pointer to the initial memory location
+ // $2 = value to be written in memory
+ // $3 = length in bytes
+ // $4 = scratch register
+
+ int scratchContains=0; //< Number of the parameter in the scratch register. 0 means no param in scratch reg.
+ int allOk=0;
+
+ /* Move the outgoing parameters in the right registers (if they are not already where they should be */
+ if ($1 != ARM_R0) {
+ if($2 == ARM_R0)
+ {
+ arm_mov_reg_reg((inst), $4, ARM_R0);
+ scratchContains=2;
+ }
+ else if($3==ARM_R0)
+ {
+ arm_mov_reg_reg((inst), $4, ARM_R0);
+ scratchContains=3;
+ }
+ arm_mov_reg_reg((inst), ARM_R0, $1);
+ }
+
+ if ($2 != ARM_R1)
+ {
+ if ($3 == ARM_R1)
+ {
+ //We must save param 3, that's in ARM_R1
+ if(scratchContains==2)
+ {
+ /*scratch reg contains the parameter that will go in ARM_R1 and can't be overwritten. Copy param 3 directly to its register. */
+ arm_mov_reg_reg(inst, ARM_R2, ARM_R1);
+ allOk=1;
+ }
+ else
+ {
+ assert(scratchContains==0);
+ //Scratch reg is free. Use it to store param 3
+ arm_mov_reg_reg(inst, $4, ARM_R1);
+ scratchContains=3;
+ }
+ }
+
+ //Set param 2
+ if(scratchContains==2)
+ {
+ arm_mov_reg_reg((inst), ARM_R1, $4);
+ }
+ else
+ {
+ arm_mov_reg_reg((inst), ARM_R1, $2);
+ }
+ }
+
+ if(!allOk)
+ {
+ if($3 != ARM_R1)
+ {
+ //Param 3 still isn't in place
+ if(scratchContains==3)
+ {
+ //Get param 3 from the scratch reg
+ arm_mov_reg_reg(inst, ARM_R2, $4);
+ }
+ else
+ {
+ //Get param 3 from wherever it is
+ arm_mov_reg_reg(inst, ARM_R2, $3);
+ }
+
+ allOk=1;
+ }
+ }
+
+ arm_call(inst, jit_memset);
+}
diff -ruN libjit/jit/jit-rules-arm.sel libjit-mikyt/jit/jit-rules-arm.sel
--- libjit/jit/jit-rules-arm.sel 2008-01-24 21:12:53.000000000 +0100
+++ libjit-mikyt/jit/jit-rules-arm.sel 1970-01-01 01:00:00.000000000 +0100
@@ -1,1403 +0,0 @@
-/*
- * jit-rules-arm.sel - Instruction selector for ARM.
- *
- * Copyright (C) 2004 Southern Storm Software, Pty Ltd.
- *
- * This file is part of the libjit library.
- *
- * The libjit library is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation, either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * The libjit library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with the libjit library. If not, see
- * .
- */
-
-%inst_type arm_inst_buf
-
-/*
- * Conversion opcodes.
- */
-
-JIT_OP_TRUNC_SBYTE: unary
- [reg] -> {
- arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 24);
- arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 24);
- }
-
-JIT_OP_TRUNC_UBYTE: unary
- [reg] -> {
- arm_alu_reg_imm8(inst, ARM_AND, $1, $1, 0xFF);
- }
-
-JIT_OP_TRUNC_SHORT: unary
- [reg] -> {
- arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 16);
- arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 16);
- }
-
-JIT_OP_TRUNC_USHORT: unary
- [reg] -> {
- arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 16);
- arm_shift_reg_imm8(inst, ARM_SHR, $1, $1, 16);
- }
-
-/*
- * Arithmetic opcodes.
- */
-
-JIT_OP_IADD: binary
- [reg, immu8] -> {
- arm_alu_reg_imm8(inst, ARM_ADD, $1, $1, $2);
- }
- [reg, reg] -> {
- arm_alu_reg_reg(inst, ARM_ADD, $1, $1, $2);
- }
-
-JIT_OP_ISUB: binary
- [reg, immu8] -> {
- arm_alu_reg_imm8(inst, ARM_SUB, $1, $1, $2);
- }
- [reg, reg] -> {
- arm_alu_reg_reg(inst, ARM_SUB, $1, $1, $2);
- }
-
-JIT_OP_IMUL: binary
- [reg, immu8] -> {
- /* Handle special cases of immediate multiplies */
- switch($2)
- {
- case 0:
- {
- arm_mov_reg_imm8(inst, $1, 0);
- }
- break;
-
- case 1: break;
-
- case 2:
- {
- arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 1);
- }
- break;
-
- case 4:
- {
- arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 2);
- }
- break;
-
- case 8:
- {
- arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 3);
- }
- break;
-
- case 16:
- {
- arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 4);
- }
- break;
-
- case 32:
- {
- arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 5);
- }
- break;
-
- case 64:
- {
- arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 6);
- }
- break;
-
- case 128:
- {
- arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 7);
- }
- break;
-
- default:
- {
- arm_mov_reg_imm8(inst, ARM_WORK, $2);
- arm_mul_reg_reg(inst, $1, $1, ARM_WORK);
- }
- break;
- }
- }
- [reg, reg] -> {
- if($1 != $2)
- {
- arm_mul_reg_reg(inst, $1, $1, $2);
- }
- else
- {
- /* Cannot use the same register for both arguments */
- arm_mov_reg_reg(inst, ARM_WORK, $2);
- arm_mul_reg_reg(inst, $1, $1, ARM_WORK);
- }
- }
-
-JIT_OP_INEG: unary
- [reg] -> {
- /* -x is the same as (0 - x) */
- arm_alu_reg_imm8(inst, ARM_RSB, $1, $1, 0);
- }
-
-JIT_OP_LADD: binary
- [lreg, lreg] -> {
- arm_alu_cc_reg_reg(inst, ARM_ADD, $1, $1, $2);
- arm_alu_reg_reg(inst, ARM_ADC, %1, %1, %2);
- }
-
-JIT_OP_LSUB: binary
- [lreg, lreg] -> {
- arm_alu_cc_reg_reg(inst, ARM_SUB, $1, $1, $2);
- arm_alu_reg_reg(inst, ARM_SBC, %1, %1, %2);
- }
-
-JIT_OP_LNEG: unary
- [lreg] -> {
- arm_alu_reg(inst, ARM_MVN, $1, $1);
- arm_alu_reg(inst, ARM_MVN, %1, %1);
- arm_alu_cc_reg_imm8(inst, ARM_ADD, $1, $1, 1);
- arm_alu_reg_imm8(inst, ARM_ADC, %1, %1, 0);
- }
-
-JIT_OP_FADD (JIT_ARM_HAS_FLOAT_REGS): binary
- [freg, freg] -> {
- arm_alu_freg_freg_32(inst, ARM_ADF, $1, $1, $2);
- }
-
-JIT_OP_FSUB (JIT_ARM_HAS_FLOAT_REGS): binary
- [freg, freg] -> {
- arm_alu_freg_freg_32(inst, ARM_SUF, $1, $1, $2);
- }
-
-JIT_OP_FMUL (JIT_ARM_HAS_FLOAT_REGS): binary
- [freg, freg] -> {
- arm_alu_freg_freg_32(inst, ARM_MUF, $1, $1, $2);
- }
-
-JIT_OP_FDIV (JIT_ARM_HAS_FLOAT_REGS): binary
- [freg, freg] -> {
- arm_alu_freg_freg_32(inst, ARM_DVF, $1, $1, $2);
- }
-
-JIT_OP_FNEG (JIT_ARM_HAS_FLOAT_REGS): unary
- [freg] -> {
- arm_alu_freg_32(inst, ARM_MNF, $1, $1);
- }
-
-JIT_OP_DADD, JIT_OP_NFADD (JIT_ARM_HAS_FLOAT_REGS): binary
- [freg, freg] -> {
- arm_alu_freg_freg(inst, ARM_ADF, $1, $1, $2);
- }
-
-JIT_OP_DSUB, JIT_OP_NFSUB (JIT_ARM_HAS_FLOAT_REGS): binary
- [freg, freg] -> {
- arm_alu_freg_freg(inst, ARM_SUF, $1, $1, $2);
- }
-
-JIT_OP_DMUL, JIT_OP_NFMUL (JIT_ARM_HAS_FLOAT_REGS): binary
- [freg, freg] -> {
- arm_alu_freg_freg(inst, ARM_MUF, $1, $1, $2);
- }
-
-JIT_OP_DDIV, JIT_OP_NFDIV (JIT_ARM_HAS_FLOAT_REGS): binary
- [freg, freg] -> {
- arm_alu_freg_freg(inst, ARM_DVF, $1, $1, $2);
- }
-
-JIT_OP_DNEG, JIT_OP_NFNEG (JIT_ARM_HAS_FLOAT_REGS): unary
- [freg] -> {
- arm_alu_freg(inst, ARM_MNF, $1, $1);
- }
-
-/*
- * Bitwise opcodes.
- */
-
-JIT_OP_IAND: binary
- [reg, immu8] -> {
- arm_alu_reg_imm8(inst, ARM_AND, $1, $1, $2);
- }
- [reg, reg] -> {
- arm_alu_reg_reg(inst, ARM_AND, $1, $1, $2);
- }
-
-JIT_OP_IOR: binary
- [reg, immu8] -> {
- arm_alu_reg_imm8(inst, ARM_ORR, $1, $1, $2);
- }
- [reg, reg] -> {
- arm_alu_reg_reg(inst, ARM_ORR, $1, $1, $2);
- }
-
-JIT_OP_IXOR: binary
- [reg, immu8] -> {
- arm_alu_reg_imm8(inst, ARM_EOR, $1, $1, $2);
- }
- [reg, reg] -> {
- arm_alu_reg_reg(inst, ARM_EOR, $1, $1, $2);
- }
-
-JIT_OP_INOT: unary
- [reg] -> {
- /* MVN == "move not" */
- arm_alu_reg(inst, ARM_MVN, $1, $1);
- }
-
-JIT_OP_ISHL: binary
- [reg, imm] -> {
- arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, ($2 & 0x1F));
- }
- [reg, reg] -> {
- arm_alu_reg_imm8(inst, ARM_AND, ARM_WORK, $2, 0x1F);
- arm_shift_reg_reg(inst, ARM_SHL, $1, $1, ARM_WORK);
- }
-
-JIT_OP_ISHR: binary
- [reg, imm] -> {
- arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, ($2 & 0x1F));
- }
- [reg, reg] -> {
- arm_alu_reg_imm8(inst, ARM_AND, ARM_WORK, $2, 0x1F);
- arm_shift_reg_reg(inst, ARM_SAR, $1, $1, ARM_WORK);
- }
-
-JIT_OP_ISHR_UN: binary
- [reg, imm] -> {
- arm_shift_reg_imm8(inst, ARM_SHR, $1, $1, ($2 & 0x1F));
- }
- [reg, reg] -> {
- arm_alu_reg_imm8(inst, ARM_AND, ARM_WORK, $2, 0x1F);
- arm_shift_reg_reg(inst, ARM_SHR, $1, $1, ARM_WORK);
- }
-
-JIT_OP_LAND: binary
- [lreg, lreg] -> {
- arm_alu_reg_reg(inst, ARM_AND, $1, $1, $2);
- arm_alu_reg_reg(inst, ARM_AND, %1, %1, %2);
- }
-
-JIT_OP_LOR: binary
- [lreg, lreg] -> {
- arm_alu_reg_reg(inst, ARM_ORR, $1, $1, $2);
- arm_alu_reg_reg(inst, ARM_ORR, %1, %1, %2);
- }
-
-JIT_OP_LXOR: binary
- [lreg, lreg] -> {
- arm_alu_reg_reg(inst, ARM_EOR, $1, $1, $2);
- arm_alu_reg_reg(inst, ARM_EOR, %1, %1, %2);
- }
-
-JIT_OP_LNOT: unary
- [lreg] -> {
- arm_alu_reg(inst, ARM_MVN, $1, $1);
- arm_alu_reg(inst, ARM_MVN, %1, %1);
- }
-
-/*
- * Branch opcodes.
- */
-
-JIT_OP_BR: spill_before
- [] -> {
- /* ARM_CC_AL == "always branch" */
- output_branch(func, &inst, ARM_CC_AL, insn);
-
- /* Flush the constant pool now, to minimize the probability that
- it is accidentally flushed in the middle of a loop body */
- jit_gen_save_inst_ptr(gen, inst);
- flush_constants(gen, 1);
- jit_gen_load_inst_ptr(gen, inst);
- }
-
-JIT_OP_BR_IFALSE: unary_branch
- [reg] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, 0);
- output_branch(func, &inst, ARM_CC_EQ, insn);
- }
-
-JIT_OP_BR_ITRUE: unary_branch
- [reg] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, 0);
- output_branch(func, &inst, ARM_CC_NE, insn);
- }
-
-JIT_OP_BR_IEQ: binary_branch
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_EQ, insn);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_EQ, insn);
- }
-
-JIT_OP_BR_INE: binary_branch
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_NE, insn);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_NE, insn);
- }
-
-JIT_OP_BR_ILT: binary_branch
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_LT, insn);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_LT, insn);
- }
-
-JIT_OP_BR_ILT_UN: binary_branch
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_LT_UN, insn);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_LT_UN, insn);
- }
-
-JIT_OP_BR_ILE: binary_branch
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_LE, insn);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_LE, insn);
- }
-
-JIT_OP_BR_ILE_UN: binary_branch
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_LE_UN, insn);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_LE_UN, insn);
- }
-
-JIT_OP_BR_IGT: binary_branch
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_GT, insn);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_GT, insn);
- }
-
-JIT_OP_BR_IGT_UN: binary_branch
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_GT_UN, insn);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_GT_UN, insn);
- }
-
-JIT_OP_BR_IGE: binary_branch
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_GE, insn);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_GE, insn);
- }
-
-JIT_OP_BR_IGE_UN: binary_branch
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_GE_UN, insn);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- output_branch(func, &inst, ARM_CC_GE_UN, insn);
- }
-
-/*
- * Comparison opcodes.
- */
-
-JIT_OP_ICMP: binary
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE);
- arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE);
- arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT);
- }
-
-JIT_OP_ICMP_UN: binary
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN);
- arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT_UN);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN);
- arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT_UN);
- }
-
-JIT_OP_IEQ: binary
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_EQ);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_NE);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_EQ);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_NE);
- }
-
-JIT_OP_INE: binary
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_NE);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_EQ);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_NE);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_EQ);
- }
-
-JIT_OP_ILT: binary
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE);
- }
-
-JIT_OP_ILT_UN: binary
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT_UN);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE_UN);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT_UN);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE_UN);
- }
-
-JIT_OP_ILE: binary
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT);
- }
-
-JIT_OP_ILE_UN: binary
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE_UN);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT_UN);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE_UN);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT_UN);
- }
-
-JIT_OP_IGT: binary
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE);
- }
-
-JIT_OP_IGT_UN: binary
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN);
- }
-
-JIT_OP_IGE: binary
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT);
- }
-
-JIT_OP_IGE_UN: binary
- [reg, immu8] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE_UN);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT_UN);
- }
- [reg, reg] -> {
- arm_test_reg_reg(inst, ARM_CMP, $1, $2);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE_UN);
- arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT_UN);
- }
-
-/*
- * Pointer check opcodes.
- */
-
-JIT_OP_CHECK_NULL: unary_note
- [reg] -> {
- arm_test_reg_imm8(inst, ARM_CMP, $1, 0);
- throw_builtin(&inst, func, ARM_CC_EQ, JIT_RESULT_NULL_REFERENCE);
- }
-
-/*
- * Function calls.
- */
-
-JIT_OP_CALL:
- [] -> {
- jit_function_t func = (jit_function_t)(insn->dest);
- arm_call(inst, func->closure_entry);
- }
-
-JIT_OP_CALL_TAIL:
- [] -> {
- jit_function_t func = (jit_function_t)(insn->dest);
- arm_pop_frame_tail(inst, 0);
- arm_jump(inst, func->closure_entry);
- }
-
-JIT_OP_CALL_INDIRECT:
- [] -> {
- arm_mov_reg_reg((inst), ARM_LINK, ARM_PC);
- arm_mov_reg_reg((inst), ARM_PC, ARM_WORK);
- }
-
-JIT_OP_CALL_VTABLE_PTR:
- [] -> {
- arm_mov_reg_reg((inst), ARM_LINK, ARM_PC);
- arm_mov_reg_reg((inst), ARM_PC, ARM_WORK);
- }
-
-JIT_OP_CALL_EXTERNAL:
- [] -> {
- arm_call(inst, (void *)(insn->dest));
- }
-
-JIT_OP_RETURN:
- [] -> {
- jump_to_epilog(gen, &inst, block);
- }
-
-JIT_OP_RETURN_INT: unary_branch
- [reg] -> {
- int cpu_reg = $1;
- if(cpu_reg != ARM_R0)
- {
- arm_mov_reg_reg(inst, ARM_R0, cpu_reg);
- }
- jump_to_epilog(gen, &inst, block);
- }
-
-JIT_OP_RETURN_LONG: unary_branch
- [imm] -> {
- mov_reg_imm(gen, &inst, ARM_R0, ((jit_int *)($1))[0]);
- mov_reg_imm(gen, &inst, ARM_R1, ((jit_int *)($1))[1]);
- jump_to_epilog(gen, &inst, block);
- }
- [local] -> {
- arm_load_membase(inst, ARM_R0, ARM_FP, $1);
- arm_load_membase(inst, ARM_R1, ARM_FP, $1 + 4);
- jump_to_epilog(gen, &inst, block);
- }
- [lreg] -> {
- if($1 != 0)
- {
- arm_mov_reg_reg(inst, ARM_R0, $1);
- arm_mov_reg_reg(inst, ARM_R1, %1);
- }
- jump_to_epilog(gen, &inst, block);
- }
-
-JIT_OP_RETURN_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): unary_branch
- [freg] -> {
- if($1 != 0)
- {
- arm_alu_freg_32(inst, ARM_MVF, ARM_F0, $1);
- }
- jump_to_epilog(gen, &inst, block);
- }
-
-JIT_OP_RETURN_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual
- [] -> {
- arm_inst_buf inst;
- _jit_regs_spill_all(gen);
- _jit_gen_fix_value(insn->value1);
- jit_gen_load_inst_ptr(gen, inst);
- if(insn->value1->is_constant)
- {
- mov_reg_imm
- (gen, &inst, ARM_R0, ((int *)(insn->value1->address))[0]);
- }
- else
- {
- arm_load_membase(inst, ARM_R0, ARM_FP, insn->value1->frame_offset);
- }
- jump_to_epilog(gen, &inst, block);
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_RETURN_FLOAT64, JIT_OP_RETURN_NFLOAT
- (JIT_ARM_HAS_FLOAT_REGS): unary_branch
- [freg] -> {
- if($1 != 0)
- {
- arm_alu_freg(inst, ARM_MVF, ARM_F0, $1);
- }
- jump_to_epilog(gen, &inst, block);
- }
-
-JIT_OP_RETURN_FLOAT64, JIT_OP_RETURN_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual
- [] -> {
- arm_inst_buf inst;
- _jit_regs_spill_all(gen);
- _jit_gen_fix_value(insn->value1);
- jit_gen_load_inst_ptr(gen, inst);
- if(insn->value1->is_constant)
- {
- mov_reg_imm
- (gen, &inst, ARM_R0, ((int *)(insn->value1->address))[0]);
- mov_reg_imm
- (gen, &inst, ARM_R1, ((int *)(insn->value1->address))[1]);
- }
- else
- {
- arm_load_membase(inst, ARM_R0, ARM_FP, insn->value1->frame_offset);
- arm_load_membase(inst, ARM_R1, ARM_FP,
- insn->value1->frame_offset + 4);
- }
- jump_to_epilog(gen, &inst, block);
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_RETURN_SMALL_STRUCT: unary_branch
- [reg] -> {
- int temp_reg = $1;
- if(temp_reg < 3)
- {
- arm_mov_reg_reg(inst, ARM_WORK, temp_reg);
- temp_reg = ARM_WORK;
- }
- switch(insn->value2->address)
- {
- case 1:
- {
- arm_load_membase_byte(inst, ARM_R0, temp_reg, 0);
- }
- break;
-
- case 2:
- {
- arm_load_membase_ushort(inst, ARM_R0, temp_reg, 0);
- }
- break;
-
- case 3:
- {
- arm_load_membase_ushort(inst, ARM_R0, temp_reg, 0);
- arm_load_membase_byte(inst, ARM_R1, temp_reg, 2);
- arm_shift_reg_imm8(inst, ARM_SHL, ARM_R1, ARM_R1, 16);
- arm_alu_reg_reg(inst, ARM_ORR, ARM_R0, ARM_R0, ARM_R1);
- }
- break;
-
- case 4:
- {
- arm_load_membase(inst, ARM_R0, temp_reg, 0);
- }
- break;
-
- case 5:
- {
- arm_load_membase(inst, ARM_R0, temp_reg, 0);
- arm_load_membase_byte(inst, ARM_R1, temp_reg, 4);
- }
- break;
-
- case 6:
- {
- arm_load_membase(inst, ARM_R0, temp_reg, 0);
- arm_load_membase_ushort(inst, ARM_R1, temp_reg, 4);
- }
- break;
-
- case 7:
- {
- arm_load_membase(inst, ARM_R0, temp_reg, 0);
- arm_load_membase_ushort(inst, ARM_R1, temp_reg, 4);
- arm_load_membase_byte(inst, ARM_R2, temp_reg, 6);
- arm_shift_reg_imm8(inst, ARM_SHL, ARM_R2, ARM_R2, 16);
- arm_alu_reg_reg(inst, ARM_ORR, ARM_R1, ARM_R1, ARM_R2);
- }
- break;
-
- case 8:
- {
- arm_load_membase(inst, ARM_R0, temp_reg, 0);
- arm_load_membase(inst, ARM_R1, temp_reg, 4);
- }
- break;
- }
- jump_to_epilog(gen, &inst, block);
- }
-
-JIT_OP_SETUP_FOR_NESTED: spill_before
- [] -> {
- jit_nint nest_reg = jit_value_get_nint_constant(insn->value1);
- if(nest_reg == -1)
- {
- arm_push_reg(inst, ARM_FP);
- }
- else
- {
- arm_mov_reg_reg(inst, _jit_reg_info[nest_reg].cpu_reg, ARM_FP);
- }
- }
-
-JIT_OP_SETUP_FOR_SIBLING: spill_before
- [] -> {
- jit_nint level = jit_value_get_nint_constant(insn->value1);
- jit_nint nest_reg = jit_value_get_nint_constant(insn->value2);
- int cpu_reg;
- if(nest_reg == -1)
- {
- cpu_reg = ARM_R0;
- }
- else
- {
- cpu_reg = _jit_reg_info[nest_reg].cpu_reg;
- }
- arm_load_membase(inst, cpu_reg, ARM_FP, JIT_APPLY_PARENT_FRAME_OFFSET);
- while(level > 0)
- {
- arm_load_membase(inst, cpu_reg, cpu_reg,
- JIT_APPLY_PARENT_FRAME_OFFSET);
- --level;
- }
- if(nest_reg == -1)
- {
- arm_push_reg(inst, cpu_reg);
- }
- }
-
-JIT_OP_IMPORT:
- [] -> {
- /* TODO */
- TODO();
- }
-
-/*
- * Data manipulation.
- */
-
-JIT_OP_COPY_LOAD_SBYTE: unary
- [reg] -> {}
-
-JIT_OP_COPY_LOAD_UBYTE: unary
- [reg] -> {}
-
-JIT_OP_COPY_LOAD_SHORT: unary
- [reg] -> {}
-
-JIT_OP_COPY_LOAD_USHORT: unary
- [reg] -> {}
-
-JIT_OP_COPY_INT: unary
- [reg] -> {}
-
-JIT_OP_COPY_LONG: unary
- [lreg] -> {}
-
-JIT_OP_COPY_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): unary
- [freg] -> {}
-
-JIT_OP_COPY_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual
- [] -> {
- arm_inst_buf inst;
- _jit_regs_force_out(gen, insn->value1, 0);
- _jit_regs_force_out(gen, insn->dest, 1);
- _jit_gen_fix_value(insn->value1);
- _jit_gen_fix_value(insn->dest);
- jit_gen_load_inst_ptr(gen, inst);
- if(insn->value1->is_constant)
- {
- mov_reg_imm
- (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
- }
- else
- {
- arm_load_membase(inst, ARM_WORK, ARM_FP,
- insn->value1->frame_offset);
- }
- arm_store_membase(inst, ARM_WORK, ARM_FP, insn->dest->frame_offset);
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_COPY_FLOAT64, JIT_OP_COPY_NFLOAT (JIT_ARM_HAS_FLOAT_REGS): unary
- [freg] -> {}
-
-JIT_OP_COPY_FLOAT64, JIT_OP_COPY_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual
- [] -> {
- arm_inst_buf inst;
- _jit_regs_force_out(gen, insn->value1, 0);
- _jit_regs_force_out(gen, insn->dest, 1);
- _jit_gen_fix_value(insn->value1);
- _jit_gen_fix_value(insn->dest);
- jit_gen_load_inst_ptr(gen, inst);
- if(insn->value1->is_constant)
- {
- mov_reg_imm
- (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
- arm_store_membase(inst, ARM_WORK, ARM_FP,
- insn->dest->frame_offset);
- mov_reg_imm
- (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
- arm_store_membase(inst, ARM_WORK, ARM_FP,
- insn->dest->frame_offset + 4);
- }
- else
- {
- arm_load_membase(inst, ARM_WORK, ARM_FP,
- insn->value1->frame_offset);
- arm_store_membase(inst, ARM_WORK, ARM_FP,
- insn->dest->frame_offset);
- arm_load_membase(inst, ARM_WORK, ARM_FP,
- insn->value1->frame_offset + 4);
- arm_store_membase(inst, ARM_WORK, ARM_FP,
- insn->dest->frame_offset + 4);
- }
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_COPY_STRUCT: manual
- [] -> {
- /* TODO */
- TODO();
- }
-
-JIT_OP_COPY_STORE_BYTE: manual
- [] -> {
- arm_inst_buf inst;
- int reg;
- _jit_regs_force_out(gen, insn->dest, 1);
- _jit_gen_fix_value(insn->dest);
- reg = _jit_regs_load_value
- (gen, insn->value1, 0,
- (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
- JIT_INSN_VALUE1_LIVE)));
- jit_gen_load_inst_ptr(gen, inst);
- arm_store_membase_byte(inst, _jit_reg_info[reg].cpu_reg,
- ARM_FP, insn->dest->frame_offset);
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_COPY_STORE_SHORT: manual
- [] -> {
- arm_inst_buf inst;
- int reg;
- _jit_regs_force_out(gen, insn->dest, 1);
- _jit_gen_fix_value(insn->dest);
- reg = _jit_regs_load_value
- (gen, insn->value1, 1,
- (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
- JIT_INSN_VALUE1_LIVE)));
- jit_gen_load_inst_ptr(gen, inst);
- arm_store_membase_short(inst, _jit_reg_info[reg].cpu_reg,
- ARM_FP, insn->dest->frame_offset);
- jit_gen_save_inst_ptr(gen, inst);
- _jit_regs_free_reg(gen, reg, 1);
- }
-
-JIT_OP_ADDRESS_OF: manual
- [] -> {
- arm_inst_buf inst;
- int reg, offset;
- _jit_regs_force_out(gen, insn->value1, 0);
- _jit_gen_fix_value(insn->value1);
- jit_gen_load_inst_ptr(gen, inst);
- reg = _jit_regs_dest_value(gen, insn->dest);
- reg = _jit_reg_info[reg].cpu_reg;
- offset = insn->value1->frame_offset;
- if(offset > 0)
- {
- arm_alu_reg_imm(inst, ARM_ADD, reg, ARM_FP, offset);
- }
- else if(offset < 0)
- {
- arm_alu_reg_imm(inst, ARM_SUB, reg, ARM_FP, -offset);
- }
- else
- {
- arm_mov_reg_reg(inst, reg, ARM_FP);
- }
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-/*
- * Stack pushes and pops.
- */
-
-JIT_OP_RETURN_REG: manual
- [] -> { /* Nothing to do here */ }
-
-JIT_OP_PUSH_INT: unary_note
- [reg] -> {
- arm_push_reg(inst, $1);
- }
-
-JIT_OP_PUSH_LONG: unary_note
- [lreg] -> {
- arm_push_reg(inst, %1);
- arm_push_reg(inst, $1);
- }
-
-JIT_OP_PUSH_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): unary_note
- [freg] -> {
- arm_push_reg_float32(inst, $1);
- }
-
-JIT_OP_PUSH_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual
- [] -> {
- arm_inst_buf inst;
- _jit_regs_force_out(gen, insn->value1, 0);
- _jit_gen_fix_value(insn->value1);
- jit_gen_load_inst_ptr(gen, inst);
- if(insn->value1->is_constant)
- {
- mov_reg_imm
- (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
- }
- else
- {
- arm_load_membase(inst, ARM_WORK, ARM_FP,
- insn->value1->frame_offset);
- }
- arm_push_reg(inst, ARM_WORK);
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_PUSH_FLOAT64, JIT_OP_PUSH_NFLOAT (JIT_ARM_HAS_FLOAT_REGS): unary_note
- [freg] -> {
- arm_push_reg_float64(inst, $1);
- }
-
-JIT_OP_PUSH_FLOAT64, JIT_OP_PUSH_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual
- [] -> {
- arm_inst_buf inst;
- _jit_regs_force_out(gen, insn->value1, 0);
- _jit_gen_fix_value(insn->value1);
- jit_gen_load_inst_ptr(gen, inst);
- if(insn->value1->is_constant)
- {
- mov_reg_imm
- (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
- arm_push_reg(inst, ARM_WORK);
- mov_reg_imm
- (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
- arm_push_reg(inst, ARM_WORK);
- }
- else
- {
- arm_load_membase(inst, ARM_WORK, ARM_FP,
- insn->value1->frame_offset + 4);
- arm_push_reg(inst, ARM_WORK);
- arm_load_membase(inst, ARM_WORK, ARM_FP,
- insn->value1->frame_offset);
- arm_push_reg(inst, ARM_WORK);
- }
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_PUSH_STRUCT: unary_note
- [reg] -> {
- /* TODO */
- TODO();
- }
-
-JIT_OP_POP_STACK:
- [] -> {
- arm_alu_reg_imm(inst, ARM_ADD, ARM_SP, ARM_SP, insn->value1->address);
- }
-
-JIT_OP_FLUSH_SMALL_STRUCT:
- [] -> {
- jit_nuint size;
- jit_nint offset;
- _jit_gen_fix_value(insn->value1);
- size = jit_type_get_size(jit_value_get_type(insn->value1));
- offset = insn->value1->frame_offset;
- switch(size)
- {
- case 1:
- {
- arm_store_membase_byte(inst, ARM_R0, ARM_FP, offset);
- }
- break;
-
- case 2:
- {
- arm_store_membase_short(inst, ARM_R0, ARM_FP, offset);
- }
- break;
-
- case 3:
- {
- arm_mov_reg_reg(inst, ARM_R1, ARM_R0);
- arm_store_membase_short(inst, ARM_R0, ARM_FP, offset);
- arm_shift_reg_imm8(inst, ARM_SHR, ARM_R0, ARM_R1, 16);
- arm_store_membase_byte(inst, ARM_R0, ARM_FP, offset + 2);
- }
- break;
-
- case 4:
- {
- arm_store_membase(inst, ARM_R0, ARM_FP, offset);
- }
- break;
-
- case 5:
- {
- arm_store_membase(inst, ARM_R0, ARM_FP, offset);
- arm_store_membase_byte(inst, ARM_R1, ARM_FP, offset + 4);
- }
- break;
-
- case 6:
- {
- arm_store_membase(inst, ARM_R0, ARM_FP, offset);
- arm_store_membase_short(inst, ARM_R1, ARM_FP, offset + 4);
- }
- break;
-
- case 7:
- {
- arm_store_membase(inst, ARM_R0, ARM_FP, offset);
- arm_mov_reg_reg(inst, ARM_R2, ARM_R1);
- arm_store_membase_short(inst, ARM_R1, ARM_FP, offset + 4);
- arm_shift_reg_imm8(inst, ARM_SHR, ARM_R1, ARM_R2, 16);
- arm_store_membase_byte(inst, ARM_R1, ARM_FP, offset + 6);
- }
- break;
-
- case 8:
- {
- arm_store_membase(inst, ARM_R0, ARM_FP, offset);
- arm_store_membase(inst, ARM_R1, ARM_FP, offset + 4);
- }
- break;
- }
- }
-
-JIT_OP_SET_PARAM_INT: unary_note
- [reg] -> {
- arm_store_membase(inst, $1, ARM_SP, insn->value2->address);
- }
-
-JIT_OP_SET_PARAM_LONG: unary_note
- [lreg] -> {
- arm_store_membase(inst, $1, ARM_SP, insn->value2->address);
- arm_store_membase(inst, %1, ARM_SP, insn->value2->address + 4);
- }
-
-JIT_OP_SET_PARAM_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): unary_note
- [freg] -> {
- arm_store_membase_float32(inst, $1, ARM_SP, insn->value2->address);
- }
-
-JIT_OP_SET_PARAM_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual
- [] -> {
- arm_inst_buf inst;
- _jit_regs_force_out(gen, insn->value1, 0);
- _jit_gen_fix_value(insn->value1);
- jit_gen_load_inst_ptr(gen, inst);
- if(insn->value1->is_constant)
- {
- mov_reg_imm
- (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
- arm_store_membase
- (inst, ARM_WORK, ARM_SP, insn->value2->address);
- }
- else
- {
- arm_load_membase(inst, ARM_WORK, ARM_FP,
- insn->value1->frame_offset);
- arm_store_membase
- (inst, ARM_WORK, ARM_SP, insn->value2->address);
- }
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_SET_PARAM_FLOAT64, JIT_OP_SET_PARAM_NFLOAT
- (JIT_ARM_HAS_FLOAT_REGS): unary_note
- [freg] -> {
- arm_store_membase_float64(inst, $1, ARM_SP, insn->value2->address);
- }
-
-JIT_OP_SET_PARAM_FLOAT64, JIT_OP_SET_PARAM_NFLOAT
- (!JIT_ARM_HAS_FLOAT_REGS): manual
- [] -> {
- arm_inst_buf inst;
- _jit_regs_force_out(gen, insn->value1, 0);
- _jit_gen_fix_value(insn->value1);
- jit_gen_load_inst_ptr(gen, inst);
- if(insn->value1->is_constant)
- {
- mov_reg_imm
- (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]);
- arm_store_membase
- (inst, ARM_WORK, ARM_SP, insn->value2->address);
- mov_reg_imm
- (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[1]);
- arm_store_membase
- (inst, ARM_WORK, ARM_SP, insn->value2->address + 4);
- }
- else
- {
- arm_load_membase(inst, ARM_WORK, ARM_FP,
- insn->value1->frame_offset);
- arm_store_membase
- (inst, ARM_WORK, ARM_SP, insn->value2->address);
- arm_load_membase(inst, ARM_WORK, ARM_FP,
- insn->value1->frame_offset + 4);
- arm_store_membase
- (inst, ARM_WORK, ARM_SP, insn->value2->address + 4);
- }
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_SET_PARAM_STRUCT: unary_note
- [reg] -> {
- /* TODO */
- TODO();
- }
-
-/*
- * Pointer-relative loads and stores.
- */
-
-JIT_OP_LOAD_RELATIVE_SBYTE: unary
- [reg] -> {
- arm_load_membase_sbyte(inst, $1, $1, insn->value2->address);
- }
-
-JIT_OP_LOAD_RELATIVE_UBYTE: unary
- [reg] -> {
- arm_load_membase_byte(inst, $1, $1, insn->value2->address);
- }
-
-JIT_OP_LOAD_RELATIVE_SHORT: unary
- [reg] -> {
- arm_load_membase_short(inst, $1, $1, insn->value2->address);
- }
-
-JIT_OP_LOAD_RELATIVE_USHORT: unary
- [reg] -> {
- arm_load_membase_ushort(inst, $1, $1, insn->value2->address);
- }
-
-JIT_OP_LOAD_RELATIVE_INT: unary
- [reg] -> {
- arm_load_membase(inst, $1, $1, insn->value2->address);
- }
-
-JIT_OP_LOAD_RELATIVE_LONG: manual
- [] -> {
- arm_inst_buf inst;
- int reg = _jit_regs_load_value
- (gen, insn->value1, 0,
- (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
- JIT_INSN_VALUE1_LIVE)));
- int reg2, reg3;
- int frame_offset;
- _jit_gen_fix_value(insn->dest);
- _jit_regs_get_reg_pair(gen, reg, -1, -1, ®2, ®3);
- reg = _jit_reg_info[reg].cpu_reg;
- reg2 = _jit_reg_info[reg2].cpu_reg;
- reg3 = _jit_reg_info[reg3].cpu_reg;
- frame_offset = insn->dest->frame_offset;
- jit_gen_load_inst_ptr(gen, inst);
- arm_load_membase(inst, reg2, reg, insn->value2->address);
- arm_load_membase(inst, reg3, reg, insn->value2->address + 4);
- arm_store_membase(inst, reg2, ARM_FP, frame_offset);
- arm_store_membase(inst, reg3, ARM_FP, frame_offset + 4);
- insn->dest->in_frame = 1;
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_LOAD_RELATIVE_FLOAT32: manual
- [] -> {
- /* TODO */
- TODO();
- }
-
-JIT_OP_LOAD_RELATIVE_FLOAT64, JIT_OP_LOAD_RELATIVE_NFLOAT: manual
- [] -> {
- /* TODO */
- TODO();
- }
-
-JIT_OP_LOAD_RELATIVE_STRUCT: manual
- [] -> {
- /* TODO */
- TODO();
- }
-
-JIT_OP_STORE_RELATIVE_BYTE: manual
- [] -> {
- arm_inst_buf inst;
- int reg = _jit_regs_load_value
- (gen, insn->dest, 0,
- (insn->flags & (JIT_INSN_DEST_NEXT_USE |
- JIT_INSN_DEST_LIVE)));
- int reg2 = _jit_regs_load_value
- (gen, insn->value1, 0,
- (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
- JIT_INSN_VALUE1_LIVE)));
- jit_gen_load_inst_ptr(gen, inst);
- reg = _jit_reg_info[reg].cpu_reg;
- reg2 = _jit_reg_info[reg2].cpu_reg;
- arm_store_membase_byte(inst, reg2, reg, insn->value2->address);
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_STORE_RELATIVE_SHORT: manual
- [] -> {
- arm_inst_buf inst;
- int reg = _jit_regs_load_value
- (gen, insn->dest, 0,
- (insn->flags & (JIT_INSN_DEST_NEXT_USE |
- JIT_INSN_DEST_LIVE)));
- int reg2 = _jit_regs_load_value
- (gen, insn->value1, 1,
- (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
- JIT_INSN_VALUE1_LIVE)));
- jit_gen_load_inst_ptr(gen, inst);
- reg = _jit_reg_info[reg].cpu_reg;
- reg2 = _jit_reg_info[reg2].cpu_reg;
- arm_store_membase_short(inst, reg2, reg, insn->value2->address);
- jit_gen_save_inst_ptr(gen, inst);
- _jit_regs_free_reg(gen, reg2, 1);
- }
-
-JIT_OP_STORE_RELATIVE_INT: manual
- [] -> {
- arm_inst_buf inst;
- int reg = _jit_regs_load_value
- (gen, insn->dest, 0,
- (insn->flags & (JIT_INSN_DEST_NEXT_USE |
- JIT_INSN_DEST_LIVE)));
- int reg2 = _jit_regs_load_value
- (gen, insn->value1, 0,
- (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
- JIT_INSN_VALUE1_LIVE)));
- jit_gen_load_inst_ptr(gen, inst);
- reg = _jit_reg_info[reg].cpu_reg;
- reg2 = _jit_reg_info[reg2].cpu_reg;
- arm_store_membase(inst, reg2, reg, insn->value2->address);
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_STORE_RELATIVE_LONG: manual
- [] -> {
- arm_inst_buf inst;
- int reg = _jit_regs_load_value
- (gen, insn->dest, 0,
- (insn->flags & (JIT_INSN_DEST_NEXT_USE |
- JIT_INSN_DEST_LIVE)));
- int reg2, reg3;
- int frame_offset;
- _jit_regs_get_reg_pair(gen, reg, -1, -1, ®2, ®3);
- _jit_gen_fix_value(insn->value1);
- jit_gen_load_inst_ptr(gen, inst);
- reg = _jit_reg_info[reg].cpu_reg;
- reg2 = _jit_reg_info[reg2].cpu_reg;
- reg3 = _jit_reg_info[reg3].cpu_reg;
- frame_offset = insn->value1->frame_offset;
- arm_load_membase(inst, reg2, ARM_FP, frame_offset);
- arm_load_membase(inst, reg3, ARM_FP, frame_offset + 4);
- arm_store_membase(inst, reg2, reg, insn->value2->address);
- arm_store_membase(inst, reg3, reg, insn->value2->address + 4);
- jit_gen_save_inst_ptr(gen, inst);
- }
-
-JIT_OP_STORE_RELATIVE_FLOAT32: manual
- [] -> {
- /* TODO */
- TODO();
- }
-
-JIT_OP_STORE_RELATIVE_FLOAT64, JIT_OP_STORE_RELATIVE_NFLOAT: manual
- [] -> {
- /* TODO */
- TODO();
- }
-
-JIT_OP_STORE_RELATIVE_STRUCT: manual
- [] -> {
- /* TODO */
- TODO();
- }
-
-JIT_OP_ADD_RELATIVE: unary
- [reg] -> {
- if(insn->value2->address != 0)
- {
- arm_alu_reg_imm(inst, ARM_ADD, $1, $1, insn->value2->address);
- }
- }
diff -ruN libjit/jit/jit-rules.c libjit-mikyt/jit/jit-rules.c
--- libjit/jit/jit-rules.c 2008-01-24 21:12:53.000000000 +0100
+++ libjit-mikyt/jit/jit-rules.c 2009-01-26 20:51:25.000000000 +0100
@@ -2,6 +2,7 @@
* jit-rules.c - Rules that define the characteristics of the back-end.
*
* Copyright (C) 2004 Southern Storm Software, Pty Ltd.
+ * Copyright (C) 2008 Michele Tartara
*
* This file is part of the libjit library.
*
@@ -22,6 +23,7 @@
#include "jit-internal.h"
#include "jit-rules.h"
+#include
/*
* The information blocks for all registers in the system.
@@ -48,7 +50,9 @@
unsigned int max_regs;
const int *word_regs;
jit_value_t word_values[JIT_MAX_WORD_REG_PARAMS];
-
+ #ifdef JIT_BACKEND_ARM
+ char in_word;
+ #endif
} jit_param_passing_t;
/*
@@ -59,6 +63,29 @@
#define STACK_WORDS(size) \
(((size) + (sizeof(void *) - 1)) / sizeof(void *))
+#ifdef JIT_BACKEND_ARM
+/**
+ * Returns the byte alignment for a parameter of the given type
+ */
+int get_param_alignment(jit_type_t type)
+{
+ int kind=jit_type_get_kind (type);
+ if(kind==JIT_TYPE_SBYTE || kind==JIT_TYPE_UBYTE || kind==JIT_TYPE_SHORT || kind==JIT_TYPE_USHORT)
+ {
+ /*
+ * If the argument is an integral Fundamental Data Type that is
+ * smaller than a word, then it is zero- or sign-extended to a
+ * full word and its size is set to 4 bytes.
+ */
+ return 4;
+ }
+ else
+ {
+ return jit_type_get_alignment(type);
+ }
+}
+#endif
+
/*
* Allocate a word register or incoming frame position to a value.
*/
@@ -129,6 +156,37 @@
return 1;
}
+#ifdef JIT_BACKEND_ARM
+int padBetweenWords(jit_function_t func, char *padding, jit_param_passing_t *passing, int param)
+{
+ assert(func);
+ assert(padding);
+ assert(passing);
+ assert(param>=0);
+
+ /* Add needed padding words at the end of the parameter */
+ int i=padding[param];
+ while(i>0)
+ {
+ if(passing->word_regs[passing->index] != -1)
+ {
+ //Leave an empty register
+ (passing->index)++;
+ }
+ else
+ {
+ //Leave an empty stack position
+ if (!jit_insn_push(func, jit_value_create_nint_constant(func, jit_type_nint, 0)))
+ {
+ return 0;
+ }
+ }
+ i--;
+ }
+ return 1;
+}
+#endif
+
int _jit_create_entry_insns(jit_function_t func)
{
jit_type_t signature = func->signature;
@@ -141,6 +199,7 @@
unsigned int size;
jit_param_passing_t passing;
jit_nint partial_offset;
+ int has_return_ptr=0;
/* Reset the local variable frame size for this function */
func->builder->frame_size = JIT_INITIAL_FRAME_SIZE;
@@ -187,22 +246,137 @@
{
return 0;
}
+ has_return_ptr=1;
}
/* Determine the maximum number of registers that may be needed
to pass the function's parameters */
num_params = jit_type_num_params(signature);
passing.max_regs = passing.index;
+ #ifdef JIT_BACKEND_ARM
+ /* Compute correct word alignment */
+ /*
+ * Init the array containing the number of padding words to be added
+ * at the end of each parameter
+ */
+ char padding[num_params];
+ int i;
+ for (i=0; i 0);
+ size=jit_type_get_size(type);
+ char word_alignment = (alignment)/sizeof(void *);
+ if (word_alignment==0)
+ {
+ /* Alignment inside a word */
+ passing.in_word=1;
+
+ /* Add needed padding bytes inside the word */
+ while((wordIndex % alignment) != 0)
+ {
+ wordIndex++;
+ }
+
+ if (wordIndex + size > sizeof(void *))
+ {
+ //Overflow to the next word
+ byteOffset[param]=0;
+ wordIndex = size;
+ (passing.max_regs)++;
+ }
+ else
+ {
+ byteOffset[param]=wordIndex;
+ wordIndex += size;
+ }
+ //The rest of the function is only for values one or more word long
+ continue;
+ }
+ else
+ {
+ //This value is not smaller than a word
+ byteOffset[param]=-1;
+
+ if(passing.in_word)
+ {
+ /* The previous param was smaller than a word, so we have to jump to the next word */
+ (passing.max_regs)++;
+ passing.in_word=0;
+ wordIndex=0;
+ }
+
+ while((passing.max_regs % word_alignment)!=0)
+ {
+ //Add padding reg
+ (passing.max_regs)++;
+ if (!(param==0 && has_return_ptr))
+ {
+ /* There is no problem in using param-1, since the first parameter is always aligned, so we will never arrive here with param=0 */
+ assert(param!=0);
+ (padding[param-1])++;
+ }
+ else
+ {
+ assert(has_return_ptr);
+ assert(param==0);
+ return_ptr_padding++;
+ }
+
+ }
+ }
+ #endif
size = STACK_WORDS(jit_type_get_size(jit_value_get_type(value)));
passing.max_regs += size;
}
}
-
+ #ifdef JIT_BACKEND_ARM
+ /* Padding */
+ if(passing.in_word)
+ {
+ /* The last param was smaller than a word, still we have to count a full word for it */
+ (passing.max_regs)++;
+ passing.in_word=0;
+ wordIndex=0;
+ }
+
+ /* Add padding between the return pointer and the first parameter (if needed) */
+ i=return_ptr_padding;
+ while(i>0)
+ {
+ //Leave an empty register
+ (passing.index)++;
+ i--;
+ }
+ #endif
+
/* Allocate the parameter offsets */
for(param = 0; param < num_params; ++param)
{
@@ -212,13 +386,48 @@
continue;
}
type = jit_type_remove_tags(jit_value_get_type(value));
+ int offset=0;
+ #ifdef JIT_BACKEND_ARM
+ if(byteOffset[param]>=0)
+ {
+ //* We are dealing with a small param
+ if(byteOffset[param]!=0)
+ {
+ /*
+ * This is not the first small param of this word,
+ * so we have already taken its value from the
+ * incoming regs or the stack
+ */
+ assert(param!=0);
+ assert(receivedValues[param-1]);
+ receivedValues[param]=receivedValues[param-1];
+
+ //Pad if needed
+ if (!padBetweenWords(func, padding, &passing, param))
+ {
+ return 0;
+ }
+ /*
+ * Nothing else to be done for this param: it's incoming value
+ * has already been saved
+ */
+ continue;
+ }
+ else
+ {
+ /* First small param of a word */
+ receivedValues[param]=jit_value_create(func, jit_type_int);
+ value=receivedValues[param];
+ }
+ }
+ #endif
switch(type->kind)
{
case JIT_TYPE_SBYTE:
case JIT_TYPE_UBYTE:
{
if(!alloc_incoming_word
- (func, &passing, value, _jit_nint_lowest_byte()))
+ (func, &passing, value, _jit_nint_lowest_byte(offset)))
{
return 0;
}
@@ -344,7 +553,73 @@
}
break;
}
+ #ifdef JIT_BACKEND_ARM
+ //Pad if needed
+ if (!padBetweenWords(func, padding, &passing, param))
+ {
+ return 0;
+ }
+ #endif
+ }
+
+ #ifdef JIT_BACKEND_ARM
+ /* Extract small params from the received values */
+ for(param=0; param0)
+ {
+ jit_value_t offset_bits= jit_value_create_nint_constant(func, jit_type_int, (jit_nint) (offset*8));
+ final_value = jit_insn_shr(func, temp, offset_bits);
+ }
+ else
+ {
+ final_value=temp;
+ }
+ assert(final_value);
+ jit_insn_store(func, destValue, final_value);
+ }
}
+ #endif
return 1;
}
@@ -469,6 +744,58 @@
return 1;
}
+#ifdef JIT_BACKEND_ARM
+/**
+ * Add a parameter with an alignment smaller than a word
+ */
+void addSmallParam(unsigned int param, jit_type_t type, char *smallerThanWord, char *miniParamEndIndex, jit_param_passing_t *passing)
+{
+ assert(type);
+ assert(smallerThanWord);
+ assert(miniParamEndIndex);
+ assert(passing);
+
+ int size=jit_type_get_size(type);
+ int alignment=get_param_alignment(type);
+
+ assert(alignment < sizeof(void *));
+ assert(size < sizeof(void *));
+
+ /*Adding a parameter that's aligned to less than a word */
+ smallerThanWord[param]=1;
+ passing->in_word=1;
+
+ int offset;
+ if (param!=0 && smallerThanWord[param-1])
+ {
+ /* The current word already holds one small param: find out where our space starts */
+ offset=miniParamEndIndex[param-1];
+ }
+ else
+ {
+ offset=0;
+ }
+ /* Calculate the padding for byte alignment */
+ while((offset % alignment) != 0)
+ {
+ offset++;
+ }
+
+ /* Verify whether there is still space enough for this param in this word */
+ if (offset+size <= sizeof(void *))
+ {
+ /*Enough space in the current word to keep this param */
+ miniParamEndIndex[param]=offset+size;
+ }
+ else
+ {
+ /* Not enough space: use next word */
+ need_outgoing_word(passing);
+ miniParamEndIndex[param]=size;
+ }
+}
+#endif
+
int _jit_create_call_setup_insns
(jit_function_t func, jit_type_t signature,
jit_value_t *args, unsigned int num_args,
@@ -484,7 +811,39 @@
jit_value_t return_ptr;
jit_value_t partial;
unsigned int param;
-
+ #ifdef JIT_BACKEND_ARM
+ //Init the array that will store the count of needed paddings
+ int i;
+ char padding[num_args];
+ //passing.padding= padding;
+ for(i=0; i0)
+ {
+ param--;
+ if(smallerThanWord[param])
+ {
+ type = jit_type_get_param(signature, param);
+ size=jit_type_get_size(type);
+ int alignment=get_param_alignment(type);
+
+ assert(size < sizeof(void *));
+ assert(alignment < sizeof(void *));
+
+ /* Place the param value at the correct offset and put it into the word */
+ jit_value_t temp;
+
+ int offset=miniParamEndIndex[param] - size;
+ assert(offset>=0);
+
+ if (offset!=0)
+ {
+ jit_value_t offset_bits= jit_value_create_nint_constant(func, jit_type_int, (jit_nint) (offset*8));
+ temp= jit_insn_shl(func, args[param], offset_bits);
+ }
+ else
+ {
+ temp=args[param];
+ }
+
+ if(passing.in_word)
+ {
+ assert(words[param+1]);
+
+ words[param]= jit_insn_or(func, words[param+1], temp);
+ words[param+1]=0;
+ }
+ else
+ {
+ /* First part of the word */
+ words[param]=temp;
+ }
+
+ assert(words[param] != 0);
+
+ if(offset!=0)
+ {
+ //The word is still unfinished.
+ assert(smallerThanWord[param-1]);
+ passing.in_word=1;
+ //Let's go on building it
+ continue;
+ }
+ else
+ {
+ //The word is ready to be written
+ passing.in_word=0;
+ continue;
+ }
+ }
+ else
+ {
+ //The previous word has to be completely built by now
+ assert(passing.in_word==0);
+ }
+ }
+ //The last word has been built
+ assert(passing.in_word==0);
+ /*if (passing.in_word)
+ {
+ //The last word contained smaller-than-word parameters
+ assert(smallerThanWord[0]);
+ passing.in_word=0;
+ }*/
+ #endif
+
#ifdef JIT_USE_PARAM_AREA
if(passing.offset > func->builder->param_area_size)
{
@@ -636,6 +1173,70 @@
while(param > 0)
{
--param;
+ #ifdef JIT_BACKEND_ARM
+ /* Add needed padding words at the end of the parameter */
+ /* Word padding */
+ int i=padding[param];
+ while(i>0)
+ {
+ if(passing.word_regs[passing.index] != -1 || param==lastOnReg)
+ {
+ //Leave an empty register
+ (passing.index)--;
+ }
+ else
+ {
+ //Leave an empty stack position
+ if (!jit_insn_push(func, jit_value_create_nint_constant(func, jit_type_nint, 0)))
+ {
+ return 0;
+ }
+ }
+ i--;
+ }
+
+ if(smallerThanWord[param])
+ {
+ if(words[param])
+ {
+ /*
+ * There is a previously built word that contain one or more parameters
+ * smaller that a word.
+ * At least param itself is a parameter smaller than a word
+ */
+ assert(smallerThanWord[param]);
+
+ //The word is ready to be written
+ rounded_size=sizeof(void *);
+ if(rounded_size <= passing.offset)
+ {
+ /* This word is on the stack */
+ if(!push_param(func, &passing, words[param], jit_type_int))
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ /* This word is in a register */
+ if(!alloc_outgoing_word(func, &passing, words[param]))
+ {
+ return 0;
+ }
+ }
+
+ //Nothing more to be done for this param
+ continue;
+ }
+ else
+ {
+ //This param has been merged in a single word with the previous one
+ assert(param!=0);
+ assert(smallerThanWord[param-1]);
+ continue;
+ }
+ }
+ #endif
type = jit_type_get_param(signature, param);
size = (jit_nint)(jit_type_get_size(type));
rounded_size = ROUND_STACK(size);
@@ -693,6 +1294,18 @@
/* Add the structure return pointer if required */
if(return_ptr)
{
+ #ifdef JIT_BACKEND_ARM
+ /* Add needed padding words at the end of the parameter */
+ /* Word padding */
+ int i=return_ptr_padding;
+ while(i>0)
+ {
+ //Leave an empty register
+ (passing.index)--;
+ i--;
+ }
+ #endif
+
if(passing.index > 0)
{
if(!alloc_outgoing_word(func, &passing, return_ptr))
@@ -737,8 +1350,9 @@
#endif /* JIT_CDECL_WORD_REG_PARAMS */
-int _jit_int_lowest_byte(void)
-{
+int _jit_int_lowest_byte(int offset)
+{
+ assert(offset<4);
union
{
unsigned char bytes[4];
@@ -747,7 +1361,8 @@
int posn;
un.value = (jit_int)0x01020304;
posn = 0;
- while(un.bytes[posn] != 0x04)
+ unsigned char look_for=0x04-offset;
+ while(un.bytes[posn] != look_for)
{
++posn;
}
@@ -771,11 +1386,12 @@
return posn;
}
-int _jit_nint_lowest_byte(void)
+int _jit_nint_lowest_byte(int offset)
{
#ifdef JIT_NATIVE_INT32
- return _jit_int_lowest_byte();
+ return _jit_int_lowest_byte(offset);
#else
+ assert(offset < 8);
union
{
unsigned char bytes[8];
@@ -784,7 +1400,8 @@
int posn;
un.value = (jit_long)0x0102030405060708;
posn = 0;
- while(un.bytes[posn] != 0x08)
+ unsigned char look_for=0x08-offset;
+ while(un.bytes[posn] != look_for)
{
++posn;
}
diff -ruN libjit/jit/jit-rules.h libjit-mikyt/jit/jit-rules.h
--- libjit/jit/jit-rules.h 2008-03-02 18:07:06.000000000 +0100
+++ libjit-mikyt/jit/jit-rules.h 2008-12-17 17:06:34.000000000 +0100
@@ -45,8 +45,11 @@
#elif defined(__amd64) || defined(__amd64__) || defined(_x86_64) || defined(_x86_64__)
#define JIT_BACKEND_X86_64 1
#define JIT_HAVE_BACKEND 1
+#elif defined(__arm) || defined(__arm__)
+ #define JIT_BACKEND_ARM 1
+ #define JIT_HAVE_BACKEND 1
#endif
-/*#define JIT_BACKEND_ARM 1*/
+
#if !defined(JIT_HAVE_BACKEND)
#define JIT_BACKEND_INTERP 1
#endif
@@ -218,7 +221,7 @@
* Determine the byte number within a "jit_int" where the low
* order byte can be found.
*/
-int _jit_int_lowest_byte(void);
+int _jit_int_lowest_byte(int offset);
/*
* Determine the byte number within a "jit_int" where the low
@@ -230,7 +233,7 @@
* Determine the byte number within a "jit_nint" where the low
* order byte can be found.
*/
-int _jit_nint_lowest_byte(void);
+int _jit_nint_lowest_byte(int offset);
/*
* Determine the byte number within a "jit_nint" where the low
diff -ruN libjit/jit/jit-type.c libjit-mikyt/jit/jit-type.c
--- libjit/jit/jit-type.c 2008-01-24 21:12:54.000000000 +0100
+++ libjit-mikyt/jit/jit-type.c 2008-12-17 17:06:34.000000000 +0100
@@ -416,7 +416,12 @@
{
type->size = maxSize;
}
- type->alignment = maxAlign;
+ #ifdef JIT_BACKEND_ARM
+ if(maxAlign > type->alignment)
+ #endif
+ {
+ type->alignment = maxAlign;
+ }
}
/*@
diff -ruN libjit/tools/gen-apply.c libjit-mikyt/tools/gen-apply.c
--- libjit/tools/gen-apply.c 2009-01-30 20:46:01.000000000 +0100
+++ libjit-mikyt/tools/gen-apply.c 2009-02-03 10:30:54.000000000 +0100
@@ -67,6 +67,10 @@
#if defined(__x86_64__) || defined(__x86_64)
#define PLATFORM_IS_X86_64 1
#endif
+#if defined(__arm__) || defined(__arm)
+ #define PLATFORM_IS_ARM 1
+#endif
+
#if PLATFORM_IS_X86
/*