[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[dotgnu-pnet-commits] libjit ChangeLog jit/jit-gen-arm.h
From: |
Aleksey Demakov |
Subject: |
[dotgnu-pnet-commits] libjit ChangeLog jit/jit-gen-arm.h |
Date: |
Sun, 22 Mar 2009 21:22:07 +0000 |
CVSROOT: /sources/dotgnu-pnet
Module name: libjit
Changes by: Aleksey Demakov <avd> 09/03/22 21:22:07
Modified files:
. : ChangeLog
jit : jit-gen-arm.h
Log message:
add ARM codegen macros
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/libjit/ChangeLog?cvsroot=dotgnu-pnet&r1=1.408&r2=1.409
http://cvs.savannah.gnu.org/viewcvs/libjit/jit/jit-gen-arm.h?cvsroot=dotgnu-pnet&r1=1.10&r2=1.11
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/ChangeLog,v
retrieving revision 1.408
retrieving revision 1.409
diff -u -b -r1.408 -r1.409
--- ChangeLog 7 Feb 2009 16:45:18 -0000 1.408
+++ ChangeLog 22 Mar 2009 21:22:05 -0000 1.409
@@ -1,3 +1,8 @@
+2009-03-23 Michele Tartara <address@hidden>
+
+ * jit/jit-gen-arm.h: add more ARM codegen macros including VFP
+ support.
+
2009-02-07 Aleksey Demakov <address@hidden>
* gen-sel-parser.y, gen-sel-scanner.l: remove obsolete files.
@@ -11,7 +16,7 @@
2009-02-06 Michele Tartara <address@hidden>
- * jit/jit-rules.h; define JIT_BACKEND_ARM on ARM.
+ * jit/jit-rules.h: define JIT_BACKEND_ARM on ARM.
* tools/gen-apply.c: define PLATFORM_IS_ARM on ARM.
* include/jit/jit-arch-arm.h: add ARM arch header.
* jit/Makefile.am, jit/jit-rules-arm.ins, jit/jit-rules-arm.sel:
Index: jit/jit-gen-arm.h
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/jit/jit-gen-arm.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -b -r1.10 -r1.11
--- jit/jit-gen-arm.h 24 Jan 2008 20:12:52 -0000 1.10
+++ jit/jit-gen-arm.h 22 Mar 2009 21:22:06 -0000 1.11
@@ -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, 2009 Michele Tartara <address@hidden>
*
* This file is part of the libjit library.
*
@@ -20,8 +21,11 @@
* <http://www.gnu.org/licenses/>.
*/
-#ifndef _ARM_CODEGEN_H
-#define _ARM_CODEGEN_H
+#ifndef _JIT_GEN_ARM_H
+#define _JIT_GEN_ARM_H
+
+#include <assert.h>
+#include <jit-rules-arm.h>
#ifdef __cplusplus
extern "C" {
@@ -56,8 +60,9 @@
} ARM_REG;
+#ifdef defined(JIT_ARM_HAS_FPA)
/*
- * Floating-point register numbers.
+ * Floating-point register numbers for the FPA architecture.
*/
typedef enum
{
@@ -71,6 +76,40 @@
ARM_F7 = 7
} ARM_FREG;
+#endif
+
+#ifdef JIT_ARM_HAS_VFP
+/*
+ * Floating-point register numbers for the Vector Floating Point architecture.
+ */
+typedef enum
+{
+ 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;
+#endif
/*
* Condition codes.
@@ -136,6 +175,9 @@
} ARM_SHIFT;
+#ifdef defined(JIT_ARM_HAS_FPA)
+/* Floating point definitions for the FPA architecture */
+
/*
* Floating-point unary operators.
*/
@@ -179,6 +221,34 @@
} ARM_FBINARY;
+#endif /* JIT_ARM_HAS_FPA */
+
+#ifdef JIT_ARM_HAS_VFP
+/* Floating point definitions for the Vector Floating Point architecture */
+
+/*
+ * Floating-point unary operators.
+ */
+typedef enum
+{
+ ARM_MVF = 0, /* Move - FCPY */
+ ARM_MNF = 1, /* Move negative - FNEG */
+ ARM_ABS = 2 /* Absolute value - FABS */
+} ARM_FUNARY;
+
+/*
+ * Floating-point binary operators.
+ */
+typedef enum
+{
+ ARM_FADD = 0, /* Add */
+ ARM_FMUL = 1, /* Multiply */
+ ARM_FSUB = 2, /* Subtract */
+ ARM_FDIV = 4 /* Divide */
+} ARM_FBINARY;
+
+#endif /* JIT_ARM_HAS_VFP */
+
/*
* Number of registers that are used for parameters (r0-r3).
*/
@@ -382,6 +452,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.
*/
@@ -390,6 +468,17 @@
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
* ARM lacks an instruction to load a 32-bit immediate value directly.
@@ -407,6 +496,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 +528,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<<shift) into the 32-bit "reg", with zero-extension.
+ * "scratchreg" is a scratch register that has to be asked to the register
allocator; it is
+ * used only when disp!=0; if disp==0, it can have whatever value, since it
won't be used
+ */
+#define
arm_mov_reg_memindex(inst,reg,basereg,disp,indexreg,shift,size,scratchreg) \
+do { \
+ if (basereg==ARM_NOBASEREG) \
+ { \
+ fprintf(stderr, "TODO(NOBASEREG) at %s, %d\n", __FILE__,
(int)__LINE__); \
+ } \
+ else \
+ { \
+ /* Add the displacement (only if needed)*/\
+ int tempreg=(basereg); \
+ if (disp!=0) \
+ { \
+ tempreg=(scratchreg); \
+ assert(tempreg!=basereg); \
+ assert(tempreg!=indexreg); \
+ arm_alu_reg_imm((inst), ARM_ADD, (tempreg), (basereg),
(disp)); \
+ } \
+ /* Load the content, depending on its size */ \
+ switch ((size)) { \
+ case 1:
arm_load_memindex_either(inst,reg,(tempreg),indexreg,shift,0x00400000); break;
\
+ case 2:
arm_load_memindex_either(inst,reg,tempreg,indexreg,shift,0); \
+ arm_shift_reg_imm8((inst), ARM_SHL, (reg),
(reg), 16); \
+ arm_shift_reg_imm8((inst), ARM_SHR, (reg),
(reg), 16); \
+ break; \
+ case 4:
arm_load_memindex_either(inst,reg,tempreg,indexreg,shift,0); break; \
+ default: assert (0); \
+ } \
+ } \
+} while (0)
+
+/**
+ * Store the content of "reg" into a memory area of size "size" at position
basereg+disp+(indexreg<<shift)
+ * NB: the scratch register has to be asked to the register allocator.
+ * It can't be ARM_WORK, since it's already used
+ */
+#define
arm_mov_memindex_reg(inst,basereg,disp,indexreg,shift,reg,size,scratchreg) \
+do { \
+ if (basereg==ARM_NOBASEREG) \
+ { \
+ fprintf(stderr, "TODO(NOBASEREG) at %s, %d\n", __FILE__,
(int)__LINE__); \
+ } \
+ else \
+ { \
+ arm_shift_reg_imm8((inst), ARM_SHL, (ARM_WORK), (indexreg),
(shift)); \
+ arm_alu_reg_reg((inst), ARM_ADD, (scratchreg), (basereg),
ARM_WORK); \
+ arm_mov_membase_reg((inst),(scratchreg),(disp),(reg),(size))
\
+ } \
+} while (0);
+
+/*
+ * Stores the content of register "reg" in memory, at position "mem" with size
"size"
+ * NB: destroys the content of ARM_WORK
+ */
+#define arm_mov_mem_reg(inst,mem,reg,size) \
+do { \
+ arm_mov_reg_imm((inst), ARM_WORK, (mem)); \
+ switch ((size)) { \
+ case 1: arm_store_membase_byte((inst), (reg), ARM_WORK, 0);
break; \
+ case 2: arm_store_membase_short((inst), (reg), ARM_WORK, 0);
break; \
+ case 4: arm_store_membase((inst), (reg), ARM_WORK, 0); break;
\
+ default: jit_assert(0); \
+ } \
+} while (0)
+
+/*
+ * Stores the content of "imm" in memory, at position "mem" with size "size".
Uses a scratch register (scratchreg),
+ * that has to be asked to the register allocator via the [scratch reg]
parameter in the definition of the OPCODE.
+ * NB: destroys the content of ARM_WORK
+ */
+#define arm_mov_mem_imm(inst,mem,imm,size,scratchreg) \
+do { \
+ arm_mov_reg_imm((inst), (scratchreg), (imm)); \
+ arm_mov_reg_imm((inst), ARM_WORK, (mem)); \
+ switch ((size)) { \
+ case 1: arm_store_membase_byte((inst), (scratchreg), ARM_WORK,
0); break; \
+ case 2: arm_store_membase_short((inst), (scratchreg), ARM_WORK,
0); break; \
+ case 4: arm_store_membase((inst), (scratchreg), ARM_WORK, 0);
break; \
+ default: assert(0); \
+ } \
+} while (0)
+
+/**
+ * Set "size" bytes at position basereg+disp at the value of imm
+ * NB: destroys the content of scratchreg. A good choice for scratchreg is
ARM_WORK,
+ * unless the value of disp is too big to be handled by
arm_store_membase_either. In that case,
+ * it's better to require the allocation of a scratch reg by adding the
parameter [scratch reg] at the end
+ * of the parameters of the rule inside jit-rules-arm.ins that's calling this
function.
+ */
+#define arm_mov_membase_imm(inst,basereg,disp,imm,size,scratchreg) \
+do { \
+ arm_mov_reg_imm((inst), (scratchreg), imm); \
+ arm_mov_membase_reg((inst), (basereg), (disp), (scratchreg), (size));
\
+} while(0);
+
+/**
+ * Set "size" bytes at position basereg+disp at the value of reg
+ * NB: might destroy the content of ARM_WORK because of arm_store_membase
+ */
+#define arm_mov_membase_reg(inst,basereg,disp,reg,size) \
+do { \
+ switch ((size)) { \
+ case 1: arm_store_membase_byte((inst), (reg), (basereg),
(disp)); break; \
+ case 2: arm_store_membase_short((inst), (reg), (basereg),
(disp)); break; \
+ case 4: arm_store_membase((inst), (reg), (basereg), (disp));
break; \
+ default: jit_assert(0); \
+ } \
+} while(0);
+
+/**
+* Set the value of "reg" to the "size"-bytes-long value held in memory at
position basereg+disp
+* NB: can destroys the content of ARM_WORK because of arm_store_membase_short
+*/
+#define arm_mov_reg_membase(inst,reg,basereg,disp,size) \
+do { \
+ switch ((size)) { \
+ case 1: arm_load_membase_byte((inst), (reg), (basereg),
(disp)); break; \
+ case 2: arm_load_membase_short((inst), (reg), (basereg),
(disp)); break; \
+ case 4: arm_load_membase((inst), (reg), (basereg), (disp));
break; \
+ default: jit_assert(0); \
+} \
+} while(0);
+
/*
* Clear a register to zero.
*/
@@ -491,6 +718,7 @@
} \
} while (0)
+#ifdef JIT_ARM_HAS_FPA
/*
* Perform a binary operation on floating-point arguments.
*/
@@ -529,6 +757,149 @@
((unsigned
int)(sreg))); \
} while (0)
+
+#endif /* JIT_ARM_HAS_FPA */
+
+#ifdef JIT_ARM_HAS_VFP
+/**
+ * Perform a binary operation on double-precision floating-point arguments.
+ * OPC is the number indicating the operation to execute (taken from enum
ARM_FBINARY)
+ * sreg1 and sreg2 are the registers containing the first and second operand
+ * dreg is the destination register
+ */
+#define arm_alu_freg_freg(inst,opc,dreg,sreg1,sreg2) \
+ do { \
+ unsigned int mask; \
+ switch(opc) \
+ { \
+ case ARM_FADD: \
+ mask=0x0E300B00; \
+ break; \
+ case ARM_FMUL: \
+ mask=0x0E200B00; \
+ break; \
+ case ARM_FSUB: \
+ mask=0x0E300B40; \
+ break; \
+ case ARM_FDIV: \
+ mask=0x0E800B00; \
+ break; \
+ default: \
+ printf("Unimplemented binary
operation %d in %s\n", opc, __FILE__); \
+ abort(); \
+ } \
+ arm_inst_add((inst), arm_prefix(mask) | \
+ (((unsigned int)(dreg))
<< 12) | \
+ (((unsigned
int)(sreg1)) << 16) | \
+ ((unsigned
int)(sreg2))); \
+ } while (0)
+/**
+ * Perform a binary operation on single-precision floating-point arguments.
+ * OPC is the number indicating the operation to execute (taken from enum
ARM_FBINARY)
+ * sreg1 and sreg2 are the registers containing the first and second operand
+ * dreg is the destination register
+ */
+#define arm_alu_freg_freg_32(inst,opc,dreg,sreg1,sreg2) \
+do { \
+ unsigned int mask; \
+ switch(opc) \
+ { \
+ case ARM_FADD: \
+ mask=0x0E300A00; \
+ break; \
+ case ARM_FMUL: \
+ mask=0x0E200A00; \
+ break; \
+ case ARM_FSUB: \
+ mask=0x0E300A40; \
+ break; \
+ case ARM_FDIV: \
+ mask=0x0E800A00; \
+ break; \
+ default: \
+ printf("Unimplemented binary operation %d in %s\n",
opc, __FILE__); \
+ abort(); \
+ } \
+ unsigned int dreg_top_4_bits = (dreg & 0x1E) >> 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 { \
+ 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 { \
+ 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)
+
+#endif /* JIT_ARM_HAS_VFP */
/*
* Branch or jump immediate by a byte offset. The offset is
* assumed to be +/- 32 Mbytes.
@@ -598,6 +969,7 @@
/*
* Call a subroutine at a specific target location.
+ * (Equivalent to x86_call_code)
*/
#define arm_call(inst,target) \
do { \
@@ -645,6 +1017,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 +1091,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 +1103,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<<shift) into dreg, with sign extension
(is_signed==1) or zero extension (is_signed==0)
+ */
+#define
arm_widen_memindex(inst,dreg,basereg,disp,indexreg,shift,is_signed,is_half) \
+do { \
+ int scratchreg=ARM_WORK; \
+ if(is_half) \
+ { \
+
arm_mov_reg_memindex((inst),(dreg),(basereg),(disp),(indexreg),(shift),2,
scratchreg); \
+ } \
+ else \
+ { \
+
arm_mov_reg_memindex((inst),(dreg),(basereg),(disp),(indexreg),(shift),1,
scratchreg); \
+ } \
+ if(is_signed) \
+ { \
+ int shiftSize; \
+ if (is_half) \
+ { \
+ shiftSize=16; \
+ } \
+ else \
+ { \
+ shiftSize=24; \
+ } \
+ arm_shift_reg_imm8((inst), ARM_SHL, (dreg), (dreg), shiftSize);
\
+ arm_shift_reg_imm8((inst), ARM_SAR, (dreg), (dreg), shiftSize);
\
+ } \
+} while (0)
+
#define arm_load_membase_byte(inst,reg,basereg,imm) \
do { \
arm_load_membase_either((inst), (reg),
(basereg), (imm), \
@@ -749,6 +1162,8 @@
arm_alu_reg_reg((inst), ARM_ORR, (reg), (reg),
ARM_WORK); \
} while (0)
+
+#ifdef JIT_ARM_HAS_FPA
/*
* Load a floating-point value from an address into a register.
*/
@@ -791,10 +1206,209 @@
(imm), 0x00008000); \
} while (0)
-/*
- * Store a value from a register into an address.
+#endif /* JIT_ARM_HAS_FPA */
+
+#ifdef JIT_ARM_HAS_VFP
+/**
+ * FLDS (Floating-point Load, Single-precision)
+ * Loads a word from memory address basereg+imm to
+ * the single precision floating point register reg.
+ * "mask" is usually set to 0
+ */
+#define arm_load_membase_float(inst,reg,basereg,imm,mask) \
+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(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(0x0D900B00) | \
+ (((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(0x0D100B00) | \
+ (((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(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)
+
+/**
+* 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<<shift) 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_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<<shift) into the double register "dfreg"
+ * NB: the scratch register has to be asked to the register allocator.
+ * It can't be ARM_WORK, since it's already used
+ */
+#define
arm_load_memindex_float64(inst,dfreg,basereg,disp,indexreg,shift,scratchreg) \
+ do { \
+ arm_shift_reg_imm8((inst), ARM_SHL, ARM_WORK, (indexreg),
(shift)); \
+ arm_alu_reg_reg((inst), ARM_ADD, (scratchreg), (basereg),
ARM_WORK); \
+ arm_load_membase_float64((inst), (dfreg), (scratchreg),
(disp)); \
+ } while (0)
+
+/**
+ * Load the content of the 32-bits memory area at position
basereg+disp+(indexreg<<shift) into the single float register "dfreg"
+ * NB: the scratch register has to be asked to the register allocator.
+ * It can't be ARM_WORK, since it's already used
+ */
+#define
arm_load_memindex_float32(inst,dfreg,basereg,disp,indexreg,shift,scratchreg) \
+do { \
+ arm_shift_reg_imm8((inst), ARM_SHL, ARM_WORK, (indexreg), (shift));
\
+ arm_alu_reg_reg((inst), ARM_ADD, (scratchreg), (basereg), ARM_WORK);
\
+ arm_load_membase_float32((inst), (dfreg), (scratchreg), (disp));
\
+ } while (0)
+
+/**
+ * Store the content of the float register "sfreg" into the memory area at
position basereg+disp+(indexreg<<shift)
+ * 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_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<<shift)
+ * NB: the scratch register has to be asked to the register allocator.
+ * It can't be ARM_WORK, since it's already used
+ */
+#define
arm_store_memindex_float64(inst,dfreg,basereg,disp,indexreg,shift,scratchreg) \
+do { \
+ arm_shift_reg_imm8((inst), ARM_SHL, ARM_WORK, (indexreg), (shift));
\
+ arm_alu_reg_reg((inst), ARM_ADD, (scratchreg), (basereg), ARM_WORK);
\
+ arm_store_membase_float64((inst), (dfreg), (scratchreg), (disp));
\
+} while (0)
+
+/**
+ * Store the content of the single float register "dfreg" into the 32-bits
memory area at position basereg+disp+(indexreg<<shift)
+ * NB: the scratch register has to be asked to the register allocator.
+ * It can't be ARM_WORK, since it's already used
+ */
+#define
arm_store_memindex_float32(inst,dfreg,basereg,disp,indexreg,shift,scratchreg) \
+do { \
+ arm_shift_reg_imm8((inst), ARM_SHL, ARM_WORK, (indexreg), (shift));
\
+ arm_alu_reg_reg((inst), ARM_ADD, (scratchreg), (basereg), ARM_WORK);
\
+ arm_store_membase_float32((inst), (dfreg), (scratchreg), (disp));
\
+} while (0)
+
+#endif /* JIT_ARM_HAS_VFP */
+
+/**
+ * Store a value from a register (reg) into an address (basereg+imm).
*
- * Note: storing a 16-bit value destroys the value in the register.
*/
#define arm_store_membase_either(inst,reg,basereg,imm,mask) \
do { \
@@ -815,6 +1429,8 @@
} \
else \
{ \
+ assert(reg != ARM_WORK); \
+ assert(basereg!=ARM_WORK); \
arm_mov_reg_imm((inst), ARM_WORK,
__sm_offset); \
arm_inst_add((inst),
arm_prefix(0x07800000 | (mask)) | \
(((unsigned
int)(basereg)) << 16) | \
@@ -822,6 +1438,10 @@
((unsigned
int)ARM_WORK)); \
} \
} while (0)
+
+/*
+ * The ARM STR instruction. The content of "reg" will be put in memory at the
address given by the content of basereg + imm
+ */
#define arm_store_membase(inst,reg,basereg,imm) \
do { \
arm_store_membase_either((inst), (reg),
(basereg), (imm), 0); \
@@ -848,6 +1468,7 @@
arm_store_membase_short((inst), (reg),
(basereg), (imm)); \
} while (0)
+#ifdef JIT_ARM_HAS_FPA
/*
* Store a floating-point value to a memory address.
*/
@@ -900,6 +1521,209 @@
-4,
0x00208000); \
} while (0)
+#endif /* JIT_ARM_HAS_FPA */
+
+#ifdef JIT_ARM_HAS_VFP
+/**
+ * FSTS
+ * Store a floating-point value to a memory address.
+ */
+#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_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_float32((inst), (reg),
ARM_SP, -4); \
+ arm_alu_reg_imm(inst, ARM_SUB, ARM_SP, ARM_SP,
4); \
+ } 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)));
+
+#endif /* JIT_ARM_HAS_VFP */
+
/*
* Load a value from an indexed address into a register.
*/
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [dotgnu-pnet-commits] libjit ChangeLog jit/jit-gen-arm.h,
Aleksey Demakov <=