dotgnu-pnet-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Dotgnu-pnet-commits] CVS: pnet/engine arm_codegen.h,NONE,1.1 unroll_ar


From: Rhys Weatherley <address@hidden>
Subject: [Dotgnu-pnet-commits] CVS: pnet/engine arm_codegen.h,NONE,1.1 unroll_arm.c,NONE,1.1 unroll_arm_arith.c,NONE,1.1 unroll_arm_branch.c,NONE,1.1 unroll_arm_const.c,NONE,1.1 unroll_arm_conv.c,NONE,1.1 unroll_arm_ptr.c,NONE,1.1 unroll_arm_var.c,NONE,1.1 Makefile.am,1.57,1.58 cvm.c,1.40,1.41 cvm_config.h,1.5,1.6 unroll_x86.c,1.11,1.12
Date: Sun, 04 May 2003 17:45:36 -0400

Update of /cvsroot/dotgnu-pnet/pnet/engine
In directory subversions:/tmp/cvs-serv3623/engine

Modified Files:
        Makefile.am cvm.c cvm_config.h unroll_x86.c 
Added Files:
        arm_codegen.h unroll_arm.c unroll_arm_arith.c 
        unroll_arm_branch.c unroll_arm_const.c unroll_arm_conv.c 
        unroll_arm_ptr.c unroll_arm_var.c 
Log Message:


Add the ARM unroller to the engine (2-3 times improvement in performance).


--- NEW FILE ---
/*
 * arm_codegen.h - Code generation macros for the ARM processor.
 *
 * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef _ARM_CODEGEN_H
#define _ARM_CODEGEN_H

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Register numbers.
 */
typedef enum
{
        ARM_R0   = 0,
        ARM_R1   = 1,
        ARM_R2   = 2,
        ARM_R3   = 3,
        ARM_R4   = 4,
        ARM_R5   = 5,
        ARM_R6   = 6,
        ARM_R7   = 7,
        ARM_R8   = 8,
        ARM_R9   = 9,
        ARM_R10  = 10,
        ARM_R11  = 11,
        ARM_R12  = 12,
        ARM_R13  = 13,
        ARM_R14  = 14,
        ARM_R15  = 15,
        ARM_FP   = ARM_R11,                     /* Frame pointer */
        ARM_LINK = ARM_R14,                     /* Link register */
        ARM_PC   = ARM_R15,                     /* Program counter */
        ARM_WORK = ARM_R12,                     /* Work register that we can 
destroy */
        ARM_SP   = ARM_R13,                     /* Stack pointer */

} ARM_REG;

/*
 * Condition codes.
 */
typedef enum
{
        ARM_CC_EQ    = 0,                       /* Equal */
        ARM_CC_NE    = 1,                       /* Not equal */
        ARM_CC_CS    = 2,                       /* Carry set */
        ARM_CC_CC    = 3,                       /* Carry clear */
        ARM_CC_MI    = 4,                       /* Negative */
        ARM_CC_PL    = 5,                       /* Positive */
        ARM_CC_VS    = 6,                       /* Overflow set */
        ARM_CC_VC    = 7,                       /* Overflow clear */
        ARM_CC_HI    = 8,                       /* Higher */
        ARM_CC_LS    = 9,                       /* Lower or same */
        ARM_CC_GE    = 10,                      /* Signed greater than or equal 
*/
        ARM_CC_LT    = 11,                      /* Signed less than */
        ARM_CC_GT    = 12,                      /* Signed greater than */
        ARM_CC_LE    = 13,                      /* Signed less than or equal */
        ARM_CC_AL    = 14,                      /* Always */
        ARM_CC_NV    = 15,                      /* Never */
        ARM_CC_GE_UN = ARM_CC_CS,       /* Unsigned greater than or equal */
        ARM_CC_LT_UN = ARM_CC_CC,       /* Unsigned less than */
        ARM_CC_GT_UN = ARM_CC_HI,       /* Unsigned greater than */
        ARM_CC_LE_UN = ARM_CC_LS,       /* Unsigned less than or equal */

} ARM_CC;

/*
 * Arithmetic and logical operations.
 */
typedef enum
{
        ARM_AND = 0,                            /* Bitwise AND */
        ARM_EOR = 1,                            /* Bitwise XOR */
        ARM_SUB = 2,                            /* Subtract */
        ARM_RSB = 3,                            /* Reverse subtract */
        ARM_ADD = 4,                            /* Add */
        ARM_ADC = 5,                            /* Add with carry */
        ARM_SBC = 6,                            /* Subtract with carry */
        ARM_RSC = 7,                            /* Reverse subtract with carry 
*/
        ARM_TST = 8,                            /* Test with AND */
        ARM_TEQ = 9,                            /* Test with XOR */
        ARM_CMP = 10,                           /* Test with SUB (compare) */
        ARM_CMN = 11,                           /* Test with ADD */
        ARM_ORR = 12,                           /* Bitwise OR */
        ARM_MOV = 13,                           /* Move */
        ARM_BIC = 14,                           /* Test with Op1 & ~Op2 */
        ARM_MVN = 15,                           /* Bitwise NOT */

} ARM_OP;

/*
 * Shift operators.
 */
typedef enum
{
        ARM_SHL = 0,                            /* Logical left */
        ARM_SHR = 1,                            /* Logical right */
        ARM_SAR = 2,                            /* Arithmetic right */
        ARM_ROR = 3,                            /* Rotate right */

} ARM_SHIFT;

/*
 * Type for instruction pointers (word-based, not byte-based).
 */
typedef unsigned int *arm_inst_ptr;

/*
 * Build an instruction prefix from a condition code and a mask value.
 */
#define arm_build_prefix(cond,mask)     \
                        ((((unsigned int)(cond)) << 28) | ((unsigned 
int)(mask)))

/*
 * Build an "always" instruction prefix for a regular instruction.
 */
#define arm_prefix(mask)        (arm_build_prefix(ARM_CC_AL, (mask)))

/*
 * Build special "always" prefixes.
 */
#define arm_always                      (arm_build_prefix(ARM_CC_AL, 0))
#define arm_always_cc           (arm_build_prefix(ARM_CC_AL, (1 << 20)))
#define arm_always_imm          (arm_build_prefix(ARM_CC_AL, (1 << 25)))

/*
 * Arithmetic or logical operation which doesn't set condition codes.
 */
#define arm_alu_reg_reg(inst,opc,dreg,sreg1,sreg2)      \
                        do { \
                                *(inst)++ = arm_always | \
                                                        (((unsigned int)(opc)) 
<< 21) | \
                                                        (((unsigned int)(dreg)) 
<< 12) | \
                                                        (((unsigned 
int)(sreg1)) << 16) | \
                                                         ((unsigned 
int)(sreg2)); \
                        } while (0)
#define arm_alu_reg_imm8(inst,opc,dreg,sreg,imm)        \
                        do { \
                                *(inst)++ = arm_always_imm | \
                                                        (((unsigned int)(opc)) 
<< 21) | \
                                                        (((unsigned int)(dreg)) 
<< 12) | \
                                                        (((unsigned int)(sreg)) 
<< 16) | \
                                                         ((unsigned int)((imm) 
& 0xFF)); \
                        } while (0)
#define arm_alu_reg_imm8_cond(inst,opc,dreg,sreg,imm,cond)      \
                        do { \
                                *(inst)++ = arm_build_prefix((cond), (1 << 25)) 
| \
                                                        (((unsigned int)(opc)) 
<< 21) | \
                                                        (((unsigned int)(dreg)) 
<< 12) | \
                                                        (((unsigned int)(sreg)) 
<< 16) | \
                                                         ((unsigned int)((imm) 
& 0xFF)); \
                        } while (0)
#define arm_alu_reg_imm8_rotate(inst,opc,dreg,sreg,imm,rotate)  \
                        do { \
                                *(inst)++ = arm_always_imm | \
                                                        (((unsigned int)(opc)) 
<< 21) | \
                                                        (((unsigned int)(dreg)) 
<< 12) | \
                                                        (((unsigned int)(sreg)) 
<< 16) | \
                                                        (((unsigned 
int)(rotate)) << 8) | \
                                                         ((unsigned int)((imm) 
& 0xFF)); \
                        } while (0)
extern arm_inst_ptr _arm_alu_reg_imm(arm_inst_ptr inst, int opc, int dreg,
                                                                 int sreg, int 
imm, int saveWork);
#define arm_alu_reg_imm(inst,opc,dreg,sreg,imm) \
                        do { \
                                int __value = (int)(imm); \
                                if(__value >= 0 && __value < 256) \
                                { \
                                        arm_alu_reg_imm8((inst), (opc), (dreg), 
(sreg), __value); \
                                } \
                                else \
                                { \
                                        (inst) = _arm_alu_reg_imm \
                                                ((inst), (opc), (dreg), (sreg), 
__value, 0); \
                                } \
                        } while (0)
#define arm_alu_reg_imm_save_work(inst,opc,dreg,sreg,imm)       \
                        do { \
                                int __value = (int)(imm); \
                                if(__value >= 0 && __value < 256) \
                                { \
                                        arm_alu_reg_imm8((inst), (opc), (dreg), 
(sreg), __value); \
                                } \
                                else \
                                { \
                                        (inst) = _arm_alu_reg_imm \
                                                ((inst), (opc), (dreg), (sreg), 
__value, 1); \
                                } \
                        } while (0)
#define arm_alu_reg(inst,opc,dreg,sreg) \
                        do { \
                                *(inst)++ = arm_always | \
                                                        (((unsigned int)(opc)) 
<< 21) | \
                                                        (((unsigned int)(dreg)) 
<< 12) | \
                                                         ((unsigned 
int)(sreg)); \
                        } while (0)
#define arm_alu_reg_cond(inst,opc,dreg,sreg,cond)       \
                        do { \
                                *(inst)++ = arm_build_prefix((cond), 0) | \
                                                        (((unsigned int)(opc)) 
<< 21) | \
                                                        (((unsigned int)(dreg)) 
<< 12) | \
                                                         ((unsigned 
int)(sreg)); \
                        } while (0)

/*
 * Arithmetic or logical operation which sets condition codes.
 */
#define arm_alu_cc_reg_reg(inst,opc,dreg,sreg1,sreg2)   \
                        do { \
                                *(inst)++ = arm_always_cc | \
                                                        (((unsigned int)(opc)) 
<< 21) | \
                                                        (((unsigned int)(dreg)) 
<< 12) | \
                                                        (((unsigned 
int)(sreg1)) << 16) | \
                                                         ((unsigned 
int)(sreg2)); \
                        } while (0)
#define arm_alu_cc_reg_imm8(inst,opc,dreg,sreg,imm)     \
                        do { \
                                *(inst)++ = arm_always_imm | arm_always_cc | \
                                                        (((unsigned int)(opc)) 
<< 21) | \
                                                        (((unsigned int)(dreg)) 
<< 12) | \
                                                        (((unsigned int)(sreg)) 
<< 16) | \
                                                         ((unsigned int)((imm) 
& 0xFF)); \
                        } while (0)
#define arm_alu_cc_reg(inst,opc,dreg,sreg)      \
                        do { \
                                *(inst)++ = arm_always_cc | \
                                                        (((unsigned int)(opc)) 
<< 21) | \
                                                        (((unsigned int)(dreg)) 
<< 12) | \
                                                         ((unsigned 
int)(sreg)); \
                        } while (0)

/*
 * Test operation, which sets the condition codes but has no other result.
 */
#define arm_test_reg_reg(inst,opc,sreg1,sreg2)  \
                        do { \
                                arm_alu_cc_reg_reg((inst), (opc), 0, (sreg1), 
(sreg2)); \
                        } while (0)
#define arm_test_reg_imm8(inst,opc,sreg,imm)    \
                        do { \
                                arm_alu_cc_reg_imm8((inst), (opc), 0, (sreg), 
(imm)); \
                        } while (0)
#define arm_test_reg_imm(inst,opc,sreg,imm)     \
                        do { \
                                int __value = (int)(imm); \
                                if(__value >= 0 && __value < 256) \
                                { \
                                        arm_alu_cc_reg_imm8((inst), (opc), 0, 
(sreg), __value); \
                                } \
                                else \
                                { \
                                        arm_mov_reg_imm((inst), ARM_WORK, 
__value); \
                                        arm_test_reg_reg((inst), (opc), (sreg), 
ARM_WORK); \
                                } \
                        } while (0)

/*
 * Move a value between registers.
 */
#define arm_mov_reg_reg(inst,dreg,sreg) \
                        do { \
                                arm_alu_reg((inst), ARM_MOV, (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.
 * We handle the simple cases and then bail out to a function for the rest.
 */
#define arm_mov_reg_imm8(inst,reg,imm)  \
                        do { \
                                arm_alu_reg_imm8((inst), ARM_MOV, (reg), 0, 
(imm)); \
                        } while (0)
#define arm_mov_reg_imm8_rotate(inst,reg,imm,rotate)    \
                        do { \
                                arm_alu_reg_imm8_rotate((inst), ARM_MOV, (reg), 
\
                                                                                
0, (imm), (rotate)); \
                        } while (0)
extern arm_inst_ptr _arm_mov_reg_imm(arm_inst_ptr inst, int reg, int value);
#define arm_mov_reg_imm(inst,reg,imm)   \
                        do { \
                                int __value = (int)(imm); \
                                if(__value >= 0 && __value < 256) \
                                { \
                                        arm_mov_reg_imm8((inst), (reg), 
__value); \
                                } \
                                else if((reg) == ARM_PC) \
                                { \
                                        (inst) = _arm_mov_reg_imm((inst), 
ARM_WORK, __value); \
                                        arm_mov_reg_reg((inst), ARM_PC, 
ARM_WORK); \
                                } \
                                else if(__value > -256 && __value < 0) \
                                { \
                                        arm_mov_reg_imm8((inst), (reg), 
~(__value)); \
                                        arm_alu_reg((inst), ARM_MVN, (reg), 
(reg)); \
                                } \
                                else \
                                { \
                                        (inst) = _arm_mov_reg_imm((inst), 
(reg), __value); \
                                } \
                        } while (0)

/*
 * Clear a register to zero.
 */
#define arm_clear_reg(inst,reg) \
                        do { \
                                arm_mov_reg_imm8((inst), (reg), 0); \
                        } while (0)

/*
 * No-operation instruction.
 */
#define arm_nop(inst)   arm_mov_reg_reg((inst), ARM_R0, ARM_R0)

/*
 * Perform a shift operation.
 */
#define arm_shift_reg_reg(inst,opc,dreg,sreg1,sreg2) \
                        do { \
                                *(inst)++ = arm_always | \
                                                        (((unsigned 
int)ARM_MOV) << 21) | \
                                                        (((unsigned int)(dreg)) 
<< 12) | \
                                                        (((unsigned 
int)(sreg2)) << 8) | \
                                                        (((unsigned int)(opc)) 
<< 5) | \
                                                         ((unsigned int)(1 << 
4)) | \
                                                         ((unsigned 
int)(sreg1)); \
                        } while (0)
#define arm_shift_reg_imm8(inst,opc,dreg,sreg,imm) \
                        do { \
                                *(inst)++ = arm_always | \
                                                        (((unsigned 
int)ARM_MOV) << 21) | \
                                                        (((unsigned int)(dreg)) 
<< 12) | \
                                                        (((unsigned int)(opc)) 
<< 5) | \
                                                        (((unsigned int)(imm)) 
<< 7) | \
                                                         ((unsigned 
int)(sreg)); \
                        } while (0)

/*
 * Perform a multiplication instruction.  Note: ARM instruction rules
 * say that dreg should not be the same as sreg2, so we swap the order
 * of the arguments if that situation occurs.  We assume that sreg1
 * and sreg2 are distinct registers.
 */
#define arm_mul_reg_reg(inst,dreg,sreg1,sreg2)  \
                        do { \
                                if((dreg) != (sreg2)) \
                                { \
                                        *(inst)++ = arm_prefix(0x00000090) | \
                                                                (((unsigned 
int)(dreg)) << 16) | \
                                                                (((unsigned 
int)(sreg1)) << 8) | \
                                                                 ((unsigned 
int)(sreg2)); \
                                } \
                                else \
                                { \
                                        *(inst)++ = arm_prefix(0x00000090) | \
                                                                (((unsigned 
int)(dreg)) << 16) | \
                                                                (((unsigned 
int)(sreg2)) << 8) | \
                                                                 ((unsigned 
int)(sreg1)); \
                                } \
                        } while (0)

/*
 * Branch or jump immediate by a byte offset.  The offset is
 * assumed to be +/- 32 Mbytes.
 */
#define arm_branch_imm(inst,cond,imm)   \
                        do { \
                                *(inst)++ = arm_build_prefix((cond), 
0x0A000000) | \
                                                        (((unsigned 
int)(((int)(imm)) >> 2)) & \
                                                                0x00FFFFFF); \
                        } while (0)
#define arm_jump_imm(inst,imm)  arm_branch_imm((inst), ARM_CC_AL, (imm))

/*
 * Branch or jump to a specific target location.  The offset is
 * assumed to be +/- 32 Mbytes.
 */
#define arm_branch(inst,cond,target)    \
                        do { \
                                int __offset = (int)(((unsigned char 
*)(target)) - \
                                                                (((unsigned 
char *)(inst)) + 8)); \
                                arm_branch_imm((inst), (cond), __offset); \
                        } while (0)
#define arm_jump(inst,target)   arm_branch((inst), ARM_CC_AL, (target))

/*
 * Jump to a specific target location that may be greater than
 * 32 Mbytes away from the current location.
 */
#define arm_jump_long(inst,target)      \
                        do { \
                                int __offset = (int)(((unsigned char 
*)(target)) - \
                                                                (((unsigned 
char *)(inst)) + 8)); \
                                if(__offset >= -0x04000000 && __offset < 
0x04000000) \
                                { \
                                        arm_jump_imm((inst), __offset); \
                                } \
                                else \
                                { \
                                        arm_mov_reg_imm((inst), ARM_PC, 
(int)(target)); \
                                } \
                        } while (0)

/*
 * Back-patch a branch instruction.
 */
#define arm_patch(inst,target)  \
                        do { \
                                int __offset = (int)(((unsigned char 
*)(target)) - \
                                                                (((unsigned 
char *)(inst)) + 8)); \
                                __offset = (__offset >> 2) & 0x00FFFFFF; \
                                *((int *)(inst)) = (*((int *)(inst)) & 
0xFF000000) | __offset; \
                        } while (0)

/*
 * Call a subroutine immediate by a byte offset.
 */
#define arm_call_imm(inst,imm)  \
                        do { \
                                *(inst)++ = arm_prefix(0x0B000000) | \
                                                        (((unsigned 
int)(((int)(imm)) >> 2)) & \
                                                                0x00FFFFFF); \
                        } while (0)

/*
 * Call a subroutine at a specific target location.
 */
#define arm_call(inst,target)   \
                        do { \
                                int __offset = (int)(((unsigned char 
*)(target)) - \
                                                                (((unsigned 
char *)(inst)) + 8)); \
                                if(__offset >= -0x04000000 && __offset < 
0x04000000) \
                                { \
                                        arm_call_imm((inst), __offset); \
                                } \
                                else \
                                { \
                                        arm_mov_reg_imm((inst), ARM_WORK, 
(int)(target)); \
                                        arm_mov_reg_reg((inst), ARM_LINK, 
ARM_PC); \
                                        arm_mov_reg_reg((inst), ARM_PC, 
ARM_WORK); \
                                } \
                        } while (0)

/*
 * Return from a subroutine, where the return address is in the link register.
 */
#define arm_return(inst)        \
                        do { \
                                arm_mov_reg_reg((inst), ARM_PC, ARM_LINK); \
                        } while (0)

/*
 * Push a register onto the system stack.
 */
#define arm_push_reg(inst,reg)  \
                        do { \
                                *(inst)++ = arm_prefix(0x05200004) | \
                                                        (((unsigned int)ARM_SP) 
<< 16) | \
                                                        (((unsigned int)(reg)) 
<< 12); \
                        } while (0)

/*
 * Pop a register from the system stack.
 */
#define arm_pop_reg(inst,reg)   \
                        do { \
                                *(inst)++ = arm_prefix(0x04900004) | \
                                                        (((unsigned int)ARM_SP) 
<< 16) | \
                                                        (((unsigned int)(reg)) 
<< 12); \
                        } while (0)

/*
 * Load a word value from a pointer and then advance the pointer.
 */
#define arm_load_advance(inst,dreg,sreg)        \
                        do { \
                                *(inst)++ = arm_prefix(0x04900004) | \
                                                        (((unsigned int)(sreg)) 
<< 16) | \
                                                        (((unsigned int)(dreg)) 
<< 12); \
                        } while (0)

/*
 * Load a value from an address into a register.
 */
#define arm_load_membase_either(inst,reg,basereg,imm,mask)      \
                        do { \
                                int __offset = (int)(imm); \
                                if(__offset >= 0 && __offset < (1 << 12)) \
                                { \
                                        *(inst)++ = arm_prefix(0x05900000 | 
(mask)) | \
                                                                (((unsigned 
int)(basereg)) << 16) | \
                                                                (((unsigned 
int)(reg)) << 12) | \
                                                                 ((unsigned 
int)__offset); \
                                } \
                                else if(__offset > -(1 << 12) && __offset < 0) \
                                { \
                                        *(inst)++ = arm_prefix(0x05100000 | 
(mask)) | \
                                                                (((unsigned 
int)(basereg)) << 16) | \
                                                                (((unsigned 
int)(reg)) << 12) | \
                                                                 ((unsigned 
int)(-__offset)); \
                                } \
                                else \
                                { \
                                        arm_mov_reg_imm((inst), ARM_WORK, 
__offset); \
                                        *(inst)++ = arm_prefix(0x07900000 | 
(mask)) | \
                                                                (((unsigned 
int)(basereg)) << 16) | \
                                                                (((unsigned 
int)(reg)) << 12) | \
                                                                 ((unsigned 
int)ARM_WORK); \
                                } \
                        } while (0)
#define arm_load_membase(inst,reg,basereg,imm)  \
                        do { \
                                arm_load_membase_either((inst), (reg), 
(basereg), (imm), 0); \
                        } while (0)
#define arm_load_membase_byte(inst,reg,basereg,imm)     \
                        do { \
                                arm_load_membase_either((inst), (reg), 
(basereg), (imm), \
                                                                                
0x00400000); \
                        } while (0)
#define arm_load_membase_sbyte(inst,reg,basereg,imm)    \
                        do { \
                                arm_load_membase_either((inst), (reg), 
(basereg), (imm), \
                                                                                
0x00400000); \
                                arm_shift_reg_imm8((inst), ARM_SHL, (reg), 
(reg), 24); \
                                arm_shift_reg_imm8((inst), ARM_SAR, (reg), 
(reg), 24); \
                        } while (0)
#define arm_load_membase_ushort(inst,reg,basereg,imm)   \
                        do { \
                                arm_load_membase_either((inst), (reg), 
(basereg), (imm), 0); \
                                arm_shift_reg_imm8((inst), ARM_SHL, (reg), 
(reg), 16); \
                                arm_shift_reg_imm8((inst), ARM_SHR, (reg), 
(reg), 16); \
                        } while (0)
#define arm_load_membase_short(inst,reg,basereg,imm)    \
                        do { \
                                arm_load_membase_either((inst), (reg), 
(basereg), (imm), 0); \
                                arm_shift_reg_imm8((inst), ARM_SHL, (reg), 
(reg), 16); \
                                arm_shift_reg_imm8((inst), ARM_SAR, (reg), 
(reg), 16); \
                        } while (0)

/*
 * Store a value from a register into an address.
 *
 * Note: storing a 16-bit value destroys the value in the register.
 */
#define arm_store_membase_either(inst,reg,basereg,imm,mask)     \
                        do { \
                                int __offset = (int)(imm); \
                                if(__offset >= 0 && __offset < (1 << 12)) \
                                { \
                                        *(inst)++ = arm_prefix(0x05800000 | 
(mask)) | \
                                                                (((unsigned 
int)(basereg)) << 16) | \
                                                                (((unsigned 
int)(reg)) << 12) | \
                                                                 ((unsigned 
int)__offset); \
                                } \
                                else if(__offset > -(1 << 12) && __offset < 0) \
                                { \
                                        *(inst)++ = arm_prefix(0x05000000 | 
(mask)) | \
                                                                (((unsigned 
int)(basereg)) << 16) | \
                                                                (((unsigned 
int)(reg)) << 12) | \
                                                                 ((unsigned 
int)(-__offset)); \
                                } \
                                else \
                                { \
                                        arm_mov_reg_imm((inst), ARM_WORK, 
__offset); \
                                        *(inst)++ = arm_prefix(0x07800000 | 
(mask)) | \
                                                                (((unsigned 
int)(basereg)) << 16) | \
                                                                (((unsigned 
int)(reg)) << 12) | \
                                                                 ((unsigned 
int)ARM_WORK); \
                                } \
                        } while (0)
#define arm_store_membase(inst,reg,basereg,imm) \
                        do { \
                                arm_store_membase_either((inst), (reg), 
(basereg), (imm), 0); \
                        } while (0)
#define arm_store_membase_byte(inst,reg,basereg,imm)    \
                        do { \
                                arm_store_membase_either((inst), (reg), 
(basereg), (imm), \
                                                                                
 0x00400000); \
                        } while (0)
#define arm_store_membase_ubyte(inst,reg,basereg,imm)   \
                        do { \
                                arm_store_membase_byte((inst), (reg), 
(basereg), (imm)); \
                        } while (0)
#define arm_store_membase_short(inst,reg,basereg,imm)   \
                        do { \
                                arm_store_membase_either((inst), (reg), 
(basereg), (imm), \
                                                                                
 0x00400000); \
                                arm_shift_reg_imm8((inst), ARM_SHR, (reg), 
(reg), 8); \
                                arm_store_membase_either((inst), (reg), 
(basereg), \
                                                                                
 (imm) + 1, 0x00400000); \
                        } while (0)
#define arm_store_membase_ushort(inst,reg,basereg,imm)  \
                        do { \
                                arm_store_membase_short((inst), (reg), 
(basereg), (imm)); \
                        } while (0)

/*
 * Load a value from an indexed address into a register.
 */
#define arm_load_memindex_either(inst,reg,basereg,indexreg,shift,mask)  \
                        do { \
                                *(inst)++ = arm_prefix(0x07900000 | (mask)) | \
                                                        (((unsigned 
int)(basereg)) << 16) | \
                                                        (((unsigned int)(reg)) 
<< 12) | \
                                                        (((unsigned 
int)(shift)) << 7) | \
                                                         ((unsigned 
int)(indexreg)); \
                        } while (0)
#define arm_load_memindex(inst,reg,basereg,indexreg)    \
                        do { \
                                arm_load_memindex_either((inst), (reg), 
(basereg), \
                                                                                
 (indexreg), 2, 0); \
                        } while (0)
#define arm_load_memindex_byte(inst,reg,basereg,indexreg)       \
                        do { \
                                arm_load_memindex_either((inst), (reg), 
(basereg), \
                                                                             
(indexreg), 0, 0x00400000); \
                        } while (0)
#define arm_load_memindex_sbyte(inst,reg,basereg,indexreg)      \
                        do { \
                                arm_load_memindex_either((inst), (reg), 
(basereg), \
                                                                             
(indexreg), 0, 0x00400000); \
                                arm_shift_reg_imm8((inst), ARM_SHL, (reg), 
(reg), 24); \
                                arm_shift_reg_imm8((inst), ARM_SAR, (reg), 
(reg), 24); \
                        } while (0)
#define arm_load_memindex_ushort(inst,reg,basereg,indexreg)     \
                        do { \
                                arm_load_memindex_either((inst), (reg), 
(basereg), \
                                                                                
 (indexreg), 1, 0); \
                                arm_shift_reg_imm8((inst), ARM_SHL, (reg), 
(reg), 16); \
                                arm_shift_reg_imm8((inst), ARM_SHR, (reg), 
(reg), 16); \
                        } while (0)
#define arm_load_memindex_short(inst,reg,basereg,indexreg)      \
                        do { \
                                arm_load_memindex_either((inst), (reg), 
(basereg), \
                                                                                
 (indexreg), 1, 0); \
                                arm_shift_reg_imm8((inst), ARM_SHL, (reg), 
(reg), 16); \
                                arm_shift_reg_imm8((inst), ARM_SAR, (reg), 
(reg), 16); \
                        } while (0)

/*
 * Store a value from a register into an indexed address.
 *
 * Note: storing a 16-bit value destroys the values in the base
 * register and the source register.
 */
#define arm_store_memindex_either(inst,reg,basereg,indexreg,shift,mask) \
                        do { \
                                *(inst)++ = arm_prefix(0x07800000 | (mask)) | \
                                                        (((unsigned 
int)(basereg)) << 16) | \
                                                        (((unsigned int)(reg)) 
<< 12) | \
                                                        (((unsigned 
int)(shift)) << 7) | \
                                                         ((unsigned 
int)(indexreg)); \
                        } while (0)
#define arm_store_memindex(inst,reg,basereg,indexreg)   \
                        do { \
                                arm_store_memindex_either((inst), (reg), 
(basereg), \
                                                                                
  (indexreg), 2, 0); \
                        } while (0)
#define arm_store_memindex_byte(inst,reg,basereg,indexreg)      \
                        do { \
                                arm_store_memindex_either((inst), (reg), 
(basereg), \
                                                                                
  (indexreg), 0, 0x00400000); \
                        } while (0)
#define arm_store_memindex_ubyte(inst,reg,basereg,indexreg)     \
                        do { \
                                arm_store_memindex_byte((inst), (reg), 
(basereg), \
                                                                                
(indexreg)); \
                        } while (0)
#define arm_store_memindex_short(inst,reg,basereg,indexreg)     \
                        do { \
                                arm_store_memindex_either((inst), (reg), 
(basereg), \
                                                                                
  (indexreg), 1, 0x00400000); \
                                arm_alu_reg_imm8((inst), ARM_ADD, (basereg), 
(basereg), 1); \
                                arm_shift_reg_imm8((inst), ARM_SHR, (reg), 
(reg), 8); \
                                arm_store_memindex_either((inst), (reg), 
(basereg), \
                                                                                
  (indexreg), 1, 0x00400000); \
                        } while (0)
#define arm_store_memindex_ushort(inst,reg,basereg,indexreg)    \
                        do { \
                                arm_store_memindex_short((inst), (reg), \
                                                                                
 (basereg), (indexreg)); \
                        } while (0)

#ifdef __cplusplus
};
#endif

#endif /* _ARM_CODEGEN_H */

--- NEW FILE ---
/*
 * unroll_arm.c - CVM unrolling module for ARM.
 *
 * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "engine.h"
#include "cvm.h"
#include "method_cache.h"
#include "cvm_config.h"
#include "cvm_format.h"
#include "arm_codegen.h"
#include "il_dumpasm.h"

#ifdef  __cplusplus
extern  "C" {
#endif

#ifdef IL_CVM_DIRECT_UNROLLED_ARM

/*
 * Registers that have a special meaning while executing code.
 */
#define REG_PC                  ARM_R4
#define REG_STACK               ARM_R5
#define REG_FRAME               ARM_R6

/*
 * Unrolled code generation state.
 */
typedef struct
{
        arm_inst_ptr out;                       /* Code output buffer */
        int             regsUsed;                       /* Registers currently 
in use */
        int             regsSaved;                      /* Fixed registers that 
were saved */
        int             pseudoStack[16];        /* Registers that make up the 
pseudo stack */
        int             pseudoStackSize;        /* Size of the pseudo stack */
        int             stackHeight;            /* Current virtual height of 
CVM stack */
        long    cachedLocal;            /* Local variable that was just stored 
*/
        int             cachedReg;                      /* Register for 
variable that was stored */
        int             thisValidated;          /* "this" has been checked for 
NULL */

} ARMUnroll;

/*
 * Flag bits for determining if certain registers are in use or not.
 */
#define REG_R0_MASK                     (1 << ARM_R0)
#define REG_R1_MASK                     (1 << ARM_R1)
#define REG_R2_MASK                     (1 << ARM_R2)
#define REG_R3_MASK                     (1 << ARM_R3)
#define REG_R4_MASK                     (1 << ARM_R4)
#define REG_R5_MASK                     (1 << ARM_R5)
#define REG_R6_MASK                     (1 << ARM_R6)
#define REG_R7_MASK                     (1 << ARM_R7)
#define REG_R8_MASK                     (1 << ARM_R8)
#define REG_R9_MASK                     (1 << ARM_R9)
#define REG_R10_MASK            (1 << ARM_R10)
#define REG_R11_MASK            (1 << ARM_R11)
#define REG_R12_MASK            (1 << ARM_R12)
#define REG_R13_MASK            (1 << ARM_R13)
#define REG_R14_MASK            (1 << ARM_R14)
#define REG_R15_MASK            (1 << ARM_R15)

/*
 * Register allocation order for the word registers.
 */
static char const regAllocOrder[] = {ARM_R0, ARM_R1, ARM_R2, ARM_R3,
                                                                         
ARM_R4, ARM_R7, ARM_R8, ARM_R9};
#define regAllocOrderSize       (sizeof(regAllocOrder) / sizeof(char))

/*
 * Registers that must be saved on the system stack if we use them.
 */
#define REG_NEED_SAVE_MASK      (REG_R7_MASK | REG_R8_MASK | REG_R9_MASK)

/*
 * Helper routine for the complex cases of "arm_mov_reg_imm".
 */
arm_inst_ptr _arm_mov_reg_imm(arm_inst_ptr inst, int reg, int value)
{
        /* Handle bytes in various positions */
        if((value & 0x000000FF) == value)
        {
                arm_mov_reg_imm8(inst, reg, value);
                return inst;
        }
        else if((value & 0x0000FF00) == value)
        {
                arm_mov_reg_imm8_rotate(inst, reg, (value >> 8), 12);
                return inst;
        }
        else if((value & 0x00FF0000) == value)
        {
                arm_mov_reg_imm8_rotate(inst, reg, (value >> 16), 8);
                return inst;
        }
        else if((value & 0xFF000000) == value)
        {
                arm_mov_reg_imm8_rotate(inst, reg, ((value >> 24) & 0xFF), 4);
                return inst;
        }

        /* Handle inverted bytes in various positions */
        value = ~value;
        if((value & 0x000000FF) == value)
        {
                arm_mov_reg_imm8(inst, reg, value);
                arm_alu_reg(inst, ARM_MVN, reg, reg);
                return inst;
        }
        else if((value & 0x0000FF00) == value)
        {
                arm_mov_reg_imm8_rotate(inst, reg, (value >> 8), 12);
                arm_alu_reg(inst, ARM_MVN, reg, reg);
                return inst;
        }
        else if((value & 0x00FF0000) == value)
        {
                arm_mov_reg_imm8_rotate(inst, reg, (value >> 16), 8);
                arm_alu_reg(inst, ARM_MVN, reg, reg);
                return inst;
        }
        else if((value & 0xFF000000) == value)
        {
                arm_mov_reg_imm8_rotate(inst, reg, ((value >> 24) & 0xFF), 4);
                arm_alu_reg(inst, ARM_MVN, reg, reg);
                return inst;
        }

        /* Build the value the hard way, byte by byte */
        value = ~value;
        if((value & 0xFF000000) != 0)
        {
                arm_mov_reg_imm8_rotate(inst, reg, ((value >> 24) & 0xFF), 4);
                if((value & 0x00FF0000) != 0)
                {
                        arm_alu_reg_imm8_rotate
                                (inst, ARM_ADD, reg, reg, ((value >> 16) & 
0xFF), 8);
                }
                if((value & 0x0000FF00) != 0)
                {
                        arm_alu_reg_imm8_rotate
                                (inst, ARM_ADD, reg, reg, ((value >> 8) & 
0xFF), 12);
                }
                if((value & 0x000000FF) != 0)
                {
                        arm_alu_reg_imm8(inst, ARM_ADD, reg, reg, (value & 
0xFF));
                }
        }
        else if((value & 0x00FF0000) != 0)
        {
                arm_mov_reg_imm8_rotate(inst, reg, ((value >> 16) & 0xFF), 8);
                if((value & 0x0000FF00) != 0)
                {
                        arm_alu_reg_imm8_rotate
                                (inst, ARM_ADD, reg, reg, ((value >> 8) & 
0xFF), 12);
                }
                if((value & 0x000000FF) != 0)
                {
                        arm_alu_reg_imm8(inst, ARM_ADD, reg, reg, (value & 
0xFF));
                }
        }
        else if((value & 0x0000FF00) != 0)
        {
                arm_mov_reg_imm8_rotate(inst, reg, ((value >> 8) & 0xFF), 12);
                if((value & 0x000000FF) != 0)
                {
                        arm_alu_reg_imm8(inst, ARM_ADD, reg, reg, (value & 
0xFF));
                }
        }
        else
        {
                arm_mov_reg_imm8(inst, reg, (value & 0xFF));
        }
        return inst;
}

/*
 * Helper routine for the complex cases of "arm_alu_reg_imm".
 */
arm_inst_ptr _arm_alu_reg_imm(arm_inst_ptr inst, int opc,
                                                          int dreg, int sreg, 
int imm,
                                                          int saveWork)
{
        int tempreg;
        if(saveWork)
        {
                if(dreg != ARM_R2 && sreg != ARM_R2)
                {
                        tempreg = ARM_R2;
                }
                else if(dreg != ARM_R3 && sreg != ARM_R3)
                {
                        tempreg = ARM_R3;
                }
                else
                {
                        tempreg = ARM_R4;
                }
                arm_push_reg(inst, tempreg);
        }
        else
        {
                tempreg = ARM_WORK;
        }
        _arm_mov_reg_imm(inst, tempreg, imm);
        arm_alu_reg_reg(inst, opc, dreg, sreg, tempreg);
        if(saveWork)
        {
                arm_pop_reg(inst, tempreg);
        }
        return inst;
}

/*
 * Unload the machine state and jump to a particular PC.  We assume that
 * "stacktop" has already been unloaded by a call to "FixStackHeight".
 */
static void UnloadMachineState(ARMUnroll *unroll, unsigned char *pc,
                                                           unsigned char *label)
{
        int offset;
        if(!label)
        {
                /* Jump to the contents of the specified PC */
                arm_load_membase(unroll->out, REG_PC, ARM_PC, 0);
                arm_load_membase(unroll->out, ARM_PC, REG_PC, 0);
                *((unroll->out)++) = (unsigned int)pc;
        }
        else
        {
                /* Load "pc" back into the CVM interpreter's frame and
                   then jump directly to instruction handler at "label".
                   This avoids the need for an indirect jump instruction */
                arm_load_membase(unroll->out, REG_PC, ARM_PC, 0);
                offset = (int)(((unsigned char *)(label)) -
                                       (((unsigned char *)(unroll->out)) + 8));
                if(offset >= -0x04000000 && offset < 0x04000000)
                {
                        arm_jump_imm(unroll->out, offset);
                        *((unroll->out)++) = (unsigned int)pc;
                }
                else
                {
                        arm_load_membase(unroll->out, ARM_PC, ARM_PC, 0);
                        *((unroll->out)++) = (unsigned int)pc;
                        *((unroll->out)++) = (unsigned int)label;
                }
        }
}

/*
 * Flush all registers to the CVM operand stack.
 */
static void FlushRegisterStack(ARMUnroll *unroll)
{
        int index, reg;

        /* Clear the cached local information */
        unroll->cachedLocal = -1;
        unroll->cachedReg = -1;

        /* Flush the word registers from bottom-most to top-most */
        for(index = 0; index < unroll->pseudoStackSize; ++index)
        {
                reg = unroll->pseudoStack[index];
                unroll->regsUsed &= ~(1 << reg);
                arm_store_membase(unroll->out, reg, REG_STACK, 
unroll->stackHeight);
                unroll->stackHeight += 4;
        }

        /* Reset the pseudo stack size */
        unroll->pseudoStackSize = 0;
}

/*
 * Fix the height of the CVM stack to match the cached location.
 */
static void FixStackHeight(ARMUnroll *unroll)
{
        if(unroll->stackHeight > 0)
        {
                arm_alu_reg_imm(unroll->out, ARM_ADD, REG_STACK,
                                                REG_STACK, unroll->stackHeight);
        }
        else if(unroll->stackHeight < 0)
        {
                arm_alu_reg_imm(unroll->out, ARM_SUB, REG_STACK,
                                                REG_STACK, 
-(unroll->stackHeight));
        }
}

/*
 * Perform an unconditional branch to a new location.  This is
 * also used when control falls out through the end of the block.
 * In that case, "pc" is the start of the following block.
 */
static void BranchToPC(ARMUnroll *unroll, unsigned char *pc)
{
        int reg;

        /* Flush the register stack to the CVM stack */
        FlushRegisterStack(unroll);

        /* Update the REG_STACK register if necessary */
        FixStackHeight(unroll);
        unroll->stackHeight = 0;

        /* Restore the special registers that we used */
        for(reg = 15; reg >= 0; --reg)
        {
                if((unroll->regsSaved & (1 <<reg)) != 0)
                {
                        arm_pop_reg(unroll->out, reg);
                }
        }
        unroll->regsSaved = 0;

        /* Unload the machine state */
        UnloadMachineState(unroll, pc, 0);
}

/*
 * Re-execute the current instruction in the CVM interpreter,
 * to process exception conditions.
 */
static void ReExecute(ARMUnroll *unroll, unsigned char *pc,
                                          unsigned char *label)
{
        int index, reg, height;

        /* Flush the register stack, but don't change it as we will
           still need it further down the code */
        height = unroll->stackHeight;
        for(index = 0; index < unroll->pseudoStackSize; ++index)
        {
                reg = unroll->pseudoStack[index];
                arm_store_membase(unroll->out, reg, REG_STACK, height);
                height += 4;
        }

        /* Fix up the stack height */
        if(height > 0)
        {
                arm_alu_reg_imm(unroll->out, ARM_ADD, REG_STACK,
                                            REG_STACK, height);
        }
        else if(height < 0)
        {
                arm_alu_reg_imm(unroll->out, ARM_SUB, REG_STACK,
                                                REG_STACK, -height);
        }

        /* Restore the saved special registers */
        for(reg = 15; reg >= 0; --reg)
        {
                if((unroll->regsSaved & (1 <<reg)) != 0)
                {
                        arm_pop_reg(unroll->out, reg);
                }
        }

        /* Unload the machine state and jump to the specified label */
        UnloadMachineState(unroll, pc, label);
}

/*
 * Get a register that can be used to store 32-bit word values.
 */
static int GetWordRegister(ARMUnroll *unroll)
{
        int index, reg, regmask;

        /* Clear the cached local information */
        unroll->cachedLocal = -1;
        unroll->cachedReg = -1;

        /* Search for a free register */
        for(index = 0; index < regAllocOrderSize; ++index)
        {
                reg = regAllocOrder[index];
                regmask = (1 << reg);
                if((unroll->regsUsed & regmask) == 0)
                {
                        unroll->pseudoStack[(unroll->pseudoStackSize)++] = reg;
                        unroll->regsUsed |= regmask;
                        if((regmask & REG_NEED_SAVE_MASK) != 0 &&
                           (unroll->regsSaved & regmask) == 0)
                        {
                                /* Save a special register on the system stack 
*/
                                arm_push_reg(unroll->out, reg);
                                unroll->regsSaved |= regmask;
                        }
                        return reg;
                }
        }

        /* Spill the bottom-most register to the CVM stack and reuse it */
        reg = unroll->pseudoStack[0];
        for(index = 1; index < unroll->pseudoStackSize; ++index)
        {
                unroll->pseudoStack[index - 1] = unroll->pseudoStack[index];
        }
        unroll->pseudoStack[unroll->pseudoStackSize - 1] = reg;
        arm_store_membase(unroll->out, reg, REG_STACK, unroll->stackHeight);
        unroll->stackHeight += 4;
        return reg;
}

/*
 * Get a 32-bit word register, but try to reuse the previously
 * popped register if the local variable offsets are identical.
 * This is used to optimise the common case of storing to a local
 * and then immediately reloading it.  Returns -1 if the register
 * was reused.
 */
static int GetCachedWordRegister(ARMUnroll *unroll, long local)
{
        if(unroll->cachedLocal == local)
        {
                /* Push the previous register back onto the stack */
                int reg = unroll->cachedReg;
                unroll->pseudoStack[(unroll->pseudoStackSize)++] = reg;
                unroll->regsUsed |= (1 << reg);

                /* We can only do this once: use a new register if the
                   variable is loaded again */
                unroll->cachedLocal = -1;
                unroll->cachedReg = -1;

                /* Tell the caller that the top-most register was reused */
                return -1;
        }
        else
        {
                return GetWordRegister(unroll);
        }
}

/*
 * Get the top-most word value on the stack into a register.
 */
static int GetTopWordRegister(ARMUnroll *unroll)
{
        int reg;

        /* Clear the cached local information */
        unroll->cachedLocal = -1;
        unroll->cachedReg = -1;

        /* Check for an existing word register on the stack */
        if(unroll->pseudoStackSize > 0)
        {
                return unroll->pseudoStack[unroll->pseudoStackSize - 1];
        }

        /* Load the top of the CVM stack into a new register */
        reg = GetWordRegister(unroll);
        unroll->stackHeight -= 4;
        arm_load_membase(unroll->out, reg, REG_STACK, unroll->stackHeight);
        return reg;
}

/*
 * Get the two top-most word values on the stack into registers.
 * "reg1" will be the lower of the two.
 */
static void GetTopTwoWordRegisters(ARMUnroll *unroll, int *reg1, int *reg2)
{
        /* Clear the cached local information */
        unroll->cachedLocal = -1;
        unroll->cachedReg = -1;

        /* See if we already have two word registers in play */
        if(unroll->pseudoStackSize > 1)
        {
                *reg1 = unroll->pseudoStack[unroll->pseudoStackSize - 2];
                *reg2 = unroll->pseudoStack[unroll->pseudoStackSize - 1];
                return;
        }

        /* See if we have one word register in play */
        if(unroll->pseudoStackSize == 1)
        {
                /* Get the current top of stack into "reg2" */
                *reg2 = unroll->pseudoStack[0];

                /* Allocate another word register */
                *reg1 = GetWordRegister(unroll);

                /* Swap the register stack positions */
                unroll->pseudoStack[0] = *reg1;
                unroll->pseudoStack[1] = *reg2;

                /* Load the top of the CVM stack into reg1 */
                unroll->stackHeight -= 4;
                arm_load_membase(unroll->out, *reg1, REG_STACK, 
unroll->stackHeight);
                return;
        }

        /* Load the top of the CVM stack into two new registers */
        *reg1 = GetWordRegister(unroll);
        *reg2 = GetWordRegister(unroll);
        unroll->stackHeight -= 8;
        arm_load_membase(unroll->out, *reg1, REG_STACK, unroll->stackHeight);
        arm_load_membase(unroll->out, *reg2, REG_STACK, unroll->stackHeight + 
4);
}

/*
 * Get the three top-most word values on the stack into registers.
 * "reg1" will be the lowest of the three.
 */
static void GetTopThreeWordRegisters(ARMUnroll *unroll,
                                                                         int 
*reg1, int *reg2, int *reg3)
{
        /* Clear the cached local information */
        unroll->cachedLocal = -1;
        unroll->cachedReg = -1;

        /* See if we already have three word registers in play */
        if(unroll->pseudoStackSize > 2)
        {
                *reg1 = unroll->pseudoStack[unroll->pseudoStackSize - 3];
                *reg2 = unroll->pseudoStack[unroll->pseudoStackSize - 2];
                *reg3 = unroll->pseudoStack[unroll->pseudoStackSize - 1];
                return;
        }

        /* See if we have two word registers in play */
        if(unroll->pseudoStackSize == 2)
        {
                /* Get the two values that we already have loaded */
                *reg2 = unroll->pseudoStack[0];
                *reg3 = unroll->pseudoStack[1];

                /* Allocate another word register */
                *reg1 = GetWordRegister(unroll);

                /* Swap the register stack positions */
                unroll->pseudoStack[0] = *reg1;
                unroll->pseudoStack[1] = *reg2;
                unroll->pseudoStack[2] = *reg3;

                /* Load the top of the CVM stack into reg1 */
                unroll->stackHeight -= 4;
                arm_load_membase(unroll->out, *reg1, REG_STACK, 
unroll->stackHeight);
                return;
        }

        /* See if we have one word register in play */
        if(unroll->pseudoStackSize == 1)
        {
                /* Get the value that we already have loaded */
                *reg3 = unroll->pseudoStack[0];

                /* Allocate two other word registers */
                *reg1 = GetWordRegister(unroll);
                *reg2 = GetWordRegister(unroll);

                /* Swap the register stack positions */
                unroll->pseudoStack[0] = *reg1;
                unroll->pseudoStack[1] = *reg2;
                unroll->pseudoStack[2] = *reg3;

                /* Load the top of the CVM stack into reg1 and reg2 */
                unroll->stackHeight -= 8;
                arm_load_membase(unroll->out, *reg1, REG_STACK, 
unroll->stackHeight);
                arm_load_membase(unroll->out, *reg2, REG_STACK,
                                                 unroll->stackHeight + 4);
                return;
        }

        /* Load the top of the CVM stack into three new registers */
        *reg1 = GetWordRegister(unroll);
        *reg2 = GetWordRegister(unroll);
        *reg3 = GetWordRegister(unroll);
        unroll->stackHeight -= 12;
        arm_load_membase(unroll->out, *reg1, REG_STACK, unroll->stackHeight);
        arm_load_membase(unroll->out, *reg2, REG_STACK, unroll->stackHeight + 
4);
        arm_load_membase(unroll->out, *reg3, REG_STACK, unroll->stackHeight + 
8);
}

/*
 * Free the top-most register on the pseudo stack, and record the
 * local variable that it was just stored in (-1 if no local).
 */
static void FreeTopRegister(ARMUnroll *unroll, long local)
{
        int reg = unroll->pseudoStack[--(unroll->pseudoStackSize)];
        unroll->cachedLocal = local;
        unroll->cachedReg = reg;
        unroll->regsUsed &= ~(1 << reg);
}

/*
 * Peek at the top-most word register on the stack.  Returns
 * -1 if the top-most stack value is not in a word register.
 */
static int PeekTopWordRegister(ARMUnroll *unroll)
{
        if(unroll->pseudoStackSize > 0)
        {
                int reg = unroll->pseudoStack[unroll->pseudoStackSize - 1];
                unroll->cachedLocal = -1;
                unroll->cachedReg = -1;
                return reg;
        }
        return -1;
}

/*
 * Start an unrolled code section if necessary.
 */
#define UNROLL_START()  \
                        do { \
                                if(!inUnrollBlock) \
                                { \
                                        overwritePC = pc; \
                                        unrollStart = (unsigned char 
*)(unroll.out); \
                                        inUnrollBlock = 1; \
                                } \
                        } while (0)

/*
 * If an unrolled code section is in progress, then continue,
 * otherwise don't unroll the current instruction.  This is
 * typically used for branch instructions which should not be
 * unrolled at the start of a basic block.
 */
#define UNROLL_BRANCH_START()   \
                        do { \
                                if(!inUnrollBlock) \
                                { \
                                        goto defaultCase; \
                                } \
                        } while (0)

/*
 * Flush the current unrolled code section.  Note: we assume
 * that the write to "overwritePC" will be more or less atomic
 * so that any other threads in the system that are executing
 * the method will instantly thread through to the new code
 * when execution returns to "overwritePC".
 */
#define UNROLL_FLUSH()  \
                        do { \
                                *((void **)overwritePC) = unrollStart; \
                                inUnrollBlock = 0; \
                                unroll.cachedLocal = -1; \
                                unroll.thisValidated = 0; \
                        } while (0)

/*
 * Modify the "pc" variable to account for an instruction length.
 */
#define MODIFY_UNROLL_PC(len)   \
                        do { \
                                pc += (len); \
                        } while (0)

/*
 * Table that maps direct instruction pointers into opcodes.
 */
static unsigned short *ptrToOpcode;
static unsigned char *minPtrValue;
static unsigned char *maxPtrValue;

int _ILCVMUnrollInit(void)
{
        void *minPtr;
        void *maxPtr;
        void *tempPtr;
        int index;
        int size;

        /* Get the minimum and maximum label pointers from the CVM interpreter 
*/
        minPtr = CVM_LABEL_FOR_OPCODE(0);
        maxPtr = minPtr;
        for(index = 1; index < 256; ++index)
        {
                tempPtr = CVM_LABEL_FOR_OPCODE(index);
                if(tempPtr < minPtr)
                {
                        minPtr = tempPtr;
                }
                if(tempPtr > maxPtr)
                {
                        maxPtr = tempPtr;
                }
        }
        for(index = 0; index < 256; ++index)
        {
                tempPtr = CVMP_LABEL_FOR_OPCODE(index);
                if(tempPtr < minPtr)
                {
                        minPtr = tempPtr;
                }
                if(tempPtr > maxPtr)
                {
                        maxPtr = tempPtr;
                }
        }

        /* Allocate space for the table and initialize to "nop" */
        size = (int)(((unsigned char *)maxPtr) - ((unsigned char *)minPtr) + 1);
        if((ptrToOpcode = (unsigned short *)ILMalloc(size * 2)) == 0)
        {
                return 0;
        }
        ILMemZero(ptrToOpcode, size * 2);

        /* Populate the mapping table */
        for(index = 0; index < 256; ++index)
        {
                tempPtr = CVM_LABEL_FOR_OPCODE(index);
                ptrToOpcode[((unsigned char *)tempPtr) - ((unsigned char 
*)minPtr)]
                                = index;
        }
        for(index = 0; index < 256; ++index)
        {
                tempPtr = CVMP_LABEL_FOR_OPCODE(index);
                ptrToOpcode[((unsigned char *)tempPtr) - ((unsigned char 
*)minPtr)]
                                = 0x100 + index;
        }
        minPtrValue = (unsigned char *)minPtr;
        maxPtrValue = (unsigned char *)maxPtr;

        /* Ready to go */
        return 1;
}

int _ILCVMUnrollPossible(void)
{
        /* The code generator is designed for little-endian ARM configurations,
           so bail out early if the machine is running as big-endian instead */
        union 
        {
                unsigned char buf[2];
                short value;
        } test;
        test.value = 0x0102;
        return (test.buf[0] == 0x02);
}

/*
 * Minimum buffer size.  If the amount of memory in the memory
 * cache falls below this value, then we stop the unroll process.
 * This value should be big enough to handle the largest block
 * of ARM code that may be output by an unroll case followed
 * by a full flush of the register stack.
 */
#define UNROLL_BUFMIN           256

/*
 * Define this to enable debugging of translated code.
 */
/*#define UNROLL_DEBUG*/

#ifdef UNROLL_DEBUG

/*
 * Dump translated code to stdout.
 */
static void DumpCode(ILMethod *method, unsigned char *start, int len)
{
        char cmdline[BUFSIZ];
        FILE *file = fopen("/tmp/unroll.s", "w");
        if(!file)
        {
                return;
        }
        ILDumpMethodType(stdout, ILProgramItem_Image(method),
                                         ILMethod_Signature(method), 0,
                                         ILMethod_Owner(method),
                                         ILMethod_Name(method), method);
        fputs(" ->\n", stdout);
        fflush(stdout);
        while(len > 0)
        {
                fprintf(file, ".byte %d\n", (int)(*start));
                ++start;
                --len;
        }
        fclose(file);
        sprintf(cmdline, "as /tmp/unroll.s -o /tmp/unroll.o;objdump 
--adjust-vma=%ld -d /tmp/unroll.o", (long)start);
        system(cmdline);
        unlink("/tmp/unroll.s");
        unlink("/tmp/unroll.o");
        putc('\n', stdout);
        fflush(stdout);
}

#endif /* UNROLL_DEBUG */

/*
 * Include the global definitions needed by the cases.
 */
#define IL_UNROLL_GLOBAL
#include "unroll_arm_arith.c"
#include "unroll_arm_branch.c"
#include "unroll_arm_const.c"
#include "unroll_arm_conv.c"
#include "unroll_arm_ptr.c"
#include "unroll_arm_var.c"
#undef  IL_UNROLL_GLOBAL

/* Imported from "cvm_lengths.c" */
extern unsigned char const _ILCVMLengths[512];

/* Imported from "cvmc.c" */
int _ILCVMStartUnrollBlock(ILCoder *_coder, int align, ILCachePosn *posn);

int _ILCVMUnrollMethod(ILCoder *coder, unsigned char *pc, ILMethod *method)
{
        ARMUnroll unroll;
        int inUnrollBlock;
        unsigned char *inst;
        int opcode;
        unsigned char *overwritePC;
        unsigned char *unrollStart;
        int reg, reg2, reg3;
        ILCachePosn posn;

        /* Find some room in the cache */
        if(!_ILCVMStartUnrollBlock(coder, 32, &posn))
        {
                return 0;
        }
        if((posn.limit - posn.ptr) < UNROLL_BUFMIN)
        {
                /* Insufficient space to unroll the method */
                ILCacheEndMethod(&posn);
                return 0;
        }

        /* Initialize the local unroll state */
        unroll.out = (int *)posn.ptr;
        unroll.regsUsed = 0;
        unroll.regsSaved = 0;
        unroll.pseudoStackSize = 0;
        unroll.stackHeight = 0;
        unroll.cachedLocal = -1;
        unroll.cachedReg = -1;
        unroll.thisValidated = 0;
        inUnrollBlock = 0;
        overwritePC = 0;
        unrollStart = 0;

        /* Unroll the code */
        for(;;)
        {
                /* Fetch the next instruction pointer, and convert into an 
opcode */
                inst = *((void **)pc);
                if(inst >= minPtrValue && inst <= maxPtrValue)
                {
                        opcode = (int)(ptrToOpcode[inst - minPtrValue]);
                }
                else
                {
                        opcode = COP_NOP;
                }

                /* Bail out if we've reached the end of the method */
                if(opcode == COP_PREFIX)
                {
                        /* Special direct instruction that marks the end of the 
method */
                        break;
                }

                /* Bail out if we are low on space */
                if((posn.limit - ((unsigned char *)(unroll.out))) < 
UNROLL_BUFMIN)
                {
                        break;
                }

                /* Determine what to do based on the opcode */
                switch(opcode)
                {
                        #define IL_UNROLL_CASES
                        #include "unroll_arm_arith.c"
                        #include "unroll_arm_branch.c"
                        #include "unroll_arm_const.c"
                        #include "unroll_arm_conv.c"
                        #include "unroll_arm_ptr.c"
                        #include "unroll_arm_var.c"
                        #undef  IL_UNROLL_CASES

                        case COP_NOP:
                        {
                                /* The "nop" instruction is used to mark labels 
*/
                                if(inUnrollBlock)
                                {
                                        /* Branch to just after the "nop", 
because there
                                           is no point trying to execute it */
                                        BranchToPC(&unroll, pc + CVM_LEN_NONE);
                                        UNROLL_FLUSH();
                                }
                                pc += CVM_LEN_NONE;
                        }
                        break;

                        case 0x100 + COP_PREFIX_UNROLL_METHOD:
                        {
                                /* This is usually the first instruction that is
                                   replaced by unrolled code, so optimise it 
away */
                                UNROLL_START();
                                MODIFY_UNROLL_PC(CVMP_LEN_NONE);
                        }
                        break;

                        default:
                        {
                        defaultCase:
                                /* Everything else terminates an unroll block */
                                if(inUnrollBlock)
                                {
                                        BranchToPC(&unroll, pc);
                                        UNROLL_FLUSH();
                                }

                                /* Skip the instruction that could not be 
unrolled */
                                if(opcode != COP_SWITCH)
                                {
                                        pc += (int)_ILCVMLengths[opcode];
                                }
                                else
                                {
                                        pc = CVM_ARG_SWITCH_DEFAULT;
                                }
                        }
                        break;
                }
        }

        /* Flush the last block that was converted */
        if(inUnrollBlock)
        {
                BranchToPC(&unroll, pc);
                UNROLL_FLUSH();
        }

#ifdef UNROLL_DEBUG
        /* Dump the translated code */
        DumpCode(method, posn.ptr,
                     (int)(((unsigned char *)(unroll.out)) - posn.ptr));
#endif

        /* Update the method cache to reflect the final position */
        ILCacheFlush(posn.ptr, (long)(((unsigned char *)(unroll.out)) - 
posn.ptr));
        posn.ptr = (unsigned char *)(unroll.out);
        ILCacheEndMethod(&posn);
        return 1;
}

#endif /* !IL_CVM_DIRECT_UNROLLED_ARM */

#ifdef  __cplusplus
};
#endif

--- NEW FILE ---
/*
 * unroll_arm_arith.c - Arithmetic handling for ARM CVM unrolling.
 *
 * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifdef IL_UNROLL_CASES

/*
 * We don't unroll integer division because ARM doesn't have a special
 * purpose instruction for it and it is too hard to do long-hand.
 *
 * We also don't unroll floating-point arithmetic because some ARM
 * boards don't have an FPU or FPU emulation, and so the system must
 * use soft-float libraries instead.  It is too involved to figure out
 * what to output, so we let the interpreter worry about it instead.
 */

case COP_IADD:
{
        /* Add integers */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_alu_reg_reg(unroll.out, ARM_ADD, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_ISUB:
{
        /* Subtract integers */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_alu_reg_reg(unroll.out, ARM_SUB, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_IMUL:
{
        /* Multiply integers */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_mul_reg_reg(unroll.out, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_INEG:
{
        /* Negate integer */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_alu_reg_imm8(unroll.out, ARM_RSB, reg, reg, 0);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_IAND:
{
        /* Bitwise and integers */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_alu_reg_reg(unroll.out, ARM_AND, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_IOR:
{
        /* Bitwise or integers */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_alu_reg_reg(unroll.out, ARM_ORR, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_IXOR:
{
        /* Bitwise xor integers */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_alu_reg_reg(unroll.out, ARM_EOR, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_INOT:
{
        /* Bitwise not integer */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_alu_reg(unroll.out, ARM_MVN, reg, reg);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_ISHL:
case COP_ISHR:
case COP_ISHR_UN:
{
        /* Bitwise shift integers */
        int opc;
        UNROLL_START();
        if(opcode == COP_ISHL)
        {
                opc = ARM_SHL;
        }
        else if(opcode == COP_ISHR)
        {
                opc = ARM_SAR;
        }
        else
        {
                opc = ARM_SHR;
        }
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_alu_reg_imm(unroll.out, ARM_AND, reg2, reg2, 0x1F);
        arm_shift_reg_reg(unroll.out, opc, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case 0x100 + COP_PREFIX_ICMP:
{
        /* Compare integer values with -1, 0, or 1 result */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_test_reg_reg(unroll.out, ARM_CMP, reg, reg2);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 1, ARM_CC_GT);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 0, ARM_CC_LE);
        arm_alu_reg_cond(unroll.out, ARM_MVN, reg, reg, ARM_CC_LT);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVMP_LEN_NONE);
}
break;

case 0x100 + COP_PREFIX_PCMP:
case 0x100 + COP_PREFIX_ICMP_UN:
{
        /* Compare unsigned word values with -1, 0, or 1 result */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_test_reg_reg(unroll.out, ARM_CMP, reg, reg2);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 1, ARM_CC_GT_UN);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 0, ARM_CC_LE_UN);
        arm_alu_reg_cond(unroll.out, ARM_MVN, reg, reg, ARM_CC_LT_UN);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVMP_LEN_NONE);
}
break;

case 0x100 + COP_PREFIX_SETEQ:
{
        /* Set if top of stack is equal to zero */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_test_reg_imm8(unroll.out, ARM_CMP, reg, 0);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 1, ARM_CC_EQ);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 0, ARM_CC_NE);
        MODIFY_UNROLL_PC(CVMP_LEN_NONE);
}
break;

case 0x100 + COP_PREFIX_SETNE:
{
        /* Set if top of stack is not equal to zero */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_test_reg_imm8(unroll.out, ARM_CMP, reg, 0);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 1, ARM_CC_NE);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 0, ARM_CC_EQ);
        MODIFY_UNROLL_PC(CVMP_LEN_NONE);
}
break;

case 0x100 + COP_PREFIX_SETLT:
{
        /* Set if top of stack is less than zero */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_test_reg_imm8(unroll.out, ARM_CMP, reg, 0);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 1, ARM_CC_LT);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 0, ARM_CC_GE);
        MODIFY_UNROLL_PC(CVMP_LEN_NONE);
}
break;

case 0x100 + COP_PREFIX_SETLE:
{
        /* Set if top of stack is less than or equal to zero */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_test_reg_imm8(unroll.out, ARM_CMP, reg, 0);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 1, ARM_CC_LE);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 0, ARM_CC_GT);
        MODIFY_UNROLL_PC(CVMP_LEN_NONE);
}
break;

case 0x100 + COP_PREFIX_SETGT:
{
        /* Set if top of stack is greater than zero */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_test_reg_imm8(unroll.out, ARM_CMP, reg, 0);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 1, ARM_CC_GT);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 0, ARM_CC_LE);
        MODIFY_UNROLL_PC(CVMP_LEN_NONE);
}
break;

case 0x100 + COP_PREFIX_SETGE:
{
        /* Set if top of stack is greater than or equal to zero */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_test_reg_imm8(unroll.out, ARM_CMP, reg, 0);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 1, ARM_CC_GE);
        arm_alu_reg_imm8_cond(unroll.out, ARM_MOV, reg, 0, 0, ARM_CC_LT);
        MODIFY_UNROLL_PC(CVMP_LEN_NONE);
}
break;

#endif /* IL_UNROLL_CASES */

--- NEW FILE ---
/*
 * unroll_arm_branch.c - Branch handling for ARM CVM unrolling.
 *
 * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifdef IL_UNROLL_GLOBAL

/*
 * Perform a conditional branch to one of two program locations.
 * It is assumed that "cond" refers to the inverse of the condition
 * that we are really testing.
 */
static void BranchOnCondition(ARMUnroll *unroll, int cond,
                                                      unsigned char *truePC,
                                                          unsigned char 
*falsePC)
{
        arm_inst_ptr patch;
        int reg;

        /* Flush the registers and restore special values.  Because this only
           uses "mov" and "pop" operations, it will not affect the flags */
        FlushRegisterStack(unroll);
        for(reg = 15; reg >= 0; --reg)
        {
                if((unroll->regsSaved & (1 <<reg)) != 0)
                {
                        arm_pop_reg(unroll->out, reg);
                }
        }
        unroll->regsSaved = 0;

        /* Test the condition in such a way that we branch if false */
        patch = unroll->out;
        arm_branch_imm(unroll->out, cond, 0);

        /* Output the jump to the true PC */
        FixStackHeight(unroll);
        UnloadMachineState(unroll, truePC, 0);

        /* Back-patch the branch instruction to point here */
        arm_patch(patch, unroll->out);

        /* Output the jump to the false PC */
        FixStackHeight(unroll);
        unroll->stackHeight = 0;
        UnloadMachineState(unroll, falsePC, 0);
}

#elif defined(IL_UNROLL_CASES)

case COP_BR:
{
        /* Branch unconditionally to a destination */
        UNROLL_BRANCH_START();
        BranchToPC(&unroll, CVM_ARG_BRANCH_SHORT);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_BEQ:
case COP_BR_PEQ:
{
        /* Branch if equal */
        UNROLL_BRANCH_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_test_reg_reg(unroll.out, ARM_CMP, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        BranchOnCondition(&unroll, ARM_CC_NE,
                                          CVM_ARG_BRANCH_SHORT, pc + 
CVM_LEN_BRANCH);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_BNE:
case COP_BR_PNE:
{
        /* Branch if not equal */
        UNROLL_BRANCH_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_test_reg_reg(unroll.out, ARM_CMP, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        BranchOnCondition(&unroll, ARM_CC_EQ,
                                          CVM_ARG_BRANCH_SHORT, pc + 
CVM_LEN_BRANCH);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_BLT:
{
        /* Branch if less than */
        UNROLL_BRANCH_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_test_reg_reg(unroll.out, ARM_CMP, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        BranchOnCondition(&unroll, ARM_CC_GE,
                                          CVM_ARG_BRANCH_SHORT, pc + 
CVM_LEN_BRANCH);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_BLT_UN:
{
        /* Branch if unsigned less than */
        UNROLL_BRANCH_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_test_reg_reg(unroll.out, ARM_CMP, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        BranchOnCondition(&unroll, ARM_CC_GE_UN,
                                          CVM_ARG_BRANCH_SHORT, pc + 
CVM_LEN_BRANCH);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_BLE:
{
        /* Branch if less than or equal */
        UNROLL_BRANCH_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_test_reg_reg(unroll.out, ARM_CMP, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        BranchOnCondition(&unroll, ARM_CC_GT,
                                          CVM_ARG_BRANCH_SHORT, pc + 
CVM_LEN_BRANCH);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_BLE_UN:
{
        /* Branch if unsigned less than or equal */
        UNROLL_BRANCH_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_test_reg_reg(unroll.out, ARM_CMP, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        BranchOnCondition(&unroll, ARM_CC_GT_UN,
                                          CVM_ARG_BRANCH_SHORT, pc + 
CVM_LEN_BRANCH);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_BGT:
{
        /* Branch if greater than */
        UNROLL_BRANCH_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_test_reg_reg(unroll.out, ARM_CMP, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        BranchOnCondition(&unroll, ARM_CC_LE,
                                          CVM_ARG_BRANCH_SHORT, pc + 
CVM_LEN_BRANCH);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_BGT_UN:
{
        /* Branch if unsigned greater than */
        UNROLL_BRANCH_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_test_reg_reg(unroll.out, ARM_CMP, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        BranchOnCondition(&unroll, ARM_CC_LE_UN,
                                          CVM_ARG_BRANCH_SHORT, pc + 
CVM_LEN_BRANCH);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_BGE:
{
        /* Branch if greater than or equal */
        UNROLL_BRANCH_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_test_reg_reg(unroll.out, ARM_CMP, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        BranchOnCondition(&unroll, ARM_CC_LT,
                                          CVM_ARG_BRANCH_SHORT, pc + 
CVM_LEN_BRANCH);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_BGE_UN:
{
        /* Branch if unsigned greater than or equal */
        UNROLL_BRANCH_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_test_reg_reg(unroll.out, ARM_CMP, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        BranchOnCondition(&unroll, ARM_CC_LT_UN,
                                          CVM_ARG_BRANCH_SHORT, pc + 
CVM_LEN_BRANCH);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_BRTRUE:
case COP_BRNONNULL:
{
        /* Branch if non-zero */
        UNROLL_BRANCH_START();
        reg = GetTopWordRegister(&unroll);
        arm_test_reg_imm8(unroll.out, ARM_CMP, reg, 0);
        FreeTopRegister(&unroll, -1);
        BranchOnCondition(&unroll, ARM_CC_EQ,
                                          CVM_ARG_BRANCH_SHORT, pc + 
CVM_LEN_BRANCH);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_BRFALSE:
case COP_BRNULL:
{
        /* Branch if zero */
        UNROLL_BRANCH_START();
        reg = GetTopWordRegister(&unroll);
        arm_test_reg_imm8(unroll.out, ARM_CMP, reg, 0);
        FreeTopRegister(&unroll, -1);
        BranchOnCondition(&unroll, ARM_CC_NE,
                                          CVM_ARG_BRANCH_SHORT, pc + 
CVM_LEN_BRANCH);
        MODIFY_UNROLL_PC(CVM_LEN_BRANCH);
        UNROLL_FLUSH();
}
break;

case COP_SWITCH:
{
        /* Switch statement */
        arm_inst_ptr patch;
        UNROLL_BRANCH_START();
        reg = GetTopWordRegister(&unroll);
        FreeTopRegister(&unroll, -1);
        FlushRegisterStack(&unroll);
        arm_test_reg_imm(unroll.out, ARM_CMP, reg, CVM_ARG_SWITCH_LIMIT);
        patch = unroll.out;
        arm_branch_imm(unroll.out, ARM_CC_GE_UN, 0);
        FixStackHeight(&unroll);
        arm_load_membase(unroll.out, ARM_WORK, ARM_PC, 4);
        arm_load_memindex(unroll.out, REG_PC, ARM_WORK, reg);
        arm_load_membase(unroll.out, ARM_PC, REG_PC, 0);
        *((unroll.out)++) = (unsigned int)(pc + 12);
        arm_patch(patch, unroll.out);
        BranchToPC(&unroll, CVM_ARG_SWITCH_DEFAULT);
        pc = CVM_ARG_SWITCH_DEFAULT;
        UNROLL_FLUSH();
}
break;

#endif /* IL_UNROLL_CASES */

--- NEW FILE ---
/*
 * unroll_arm_const.c - Constant handling for ARM CVM unrolling.
 *
 * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifdef IL_UNROLL_CASES

case COP_LDNULL:
case COP_LDC_I4_0:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm8(unroll.out, reg, 0);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_LDC_I4_M1:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm(unroll.out, reg, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_LDC_I4_1:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm(unroll.out, reg, 1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_LDC_I4_2:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm(unroll.out, reg, 2);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_LDC_I4_3:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm(unroll.out, reg, 3);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_LDC_I4_4:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm(unroll.out, reg, 4);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_LDC_I4_5:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm(unroll.out, reg, 5);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_LDC_I4_6:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm(unroll.out, reg, 6);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_LDC_I4_7:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm(unroll.out, reg, 7);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_LDC_I4_8:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm(unroll.out, reg, 8);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_LDC_I4_S:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm(unroll.out, reg, (int)CVM_ARG_SBYTE);
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case COP_LDC_I4:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm(unroll.out, reg, (int)CVM_ARG_WORD);
        MODIFY_UNROLL_PC(CVM_LEN_WORD);
}
break;

case COP_LDTOKEN:
{
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_imm(unroll.out, reg, (int)(CVM_ARG_PTR(void *)));
        MODIFY_UNROLL_PC(CVM_LEN_PTR);
}
break;

#endif /* IL_UNROLL_CASES */

--- NEW FILE ---
/*
 * unroll_arm_conv.c - Conversion handling for ARM CVM unrolling.
 *
 * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifdef IL_UNROLL_CASES

case COP_I2B:
{
        /* Convert an integer into a byte */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_shift_reg_imm8(unroll.out, ARM_SHL, reg, reg, 24);
        arm_shift_reg_imm8(unroll.out, ARM_SAR, reg, reg, 24);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_I2UB:
{
        /* Convert an integer into an unsigned byte */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_alu_reg_imm8(unroll.out, ARM_AND, reg, reg, 0xFF);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_I2S:
{
        /* Convert an integer into a short */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_shift_reg_imm8(unroll.out, ARM_SHL, reg, reg, 16);
        arm_shift_reg_imm8(unroll.out, ARM_SAR, reg, reg, 16);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_I2US:
{
        /* Convert an integer into an unsigned short */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_shift_reg_imm8(unroll.out, ARM_SHL, reg, reg, 16);
        arm_shift_reg_imm8(unroll.out, ARM_SHR, reg, reg, 16);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

#endif /* IL_UNROLL_CASES */

--- NEW FILE ---
/*
 * unroll_arm_ptr.c - Pointer handling for ARM CVM unrolling.
 *
 * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifdef IL_UNROLL_GLOBAL

/*
 * Check the contents of a register for NULL and re-execute
 * the current instruction in the interpreter if it is.
 */
static void CheckForNull(ARMUnroll *unroll, int reg, unsigned char *pc,
                                                 unsigned char *label, int 
popReg)
{
        arm_inst_ptr patch;

        /* Check the register's contents against NULL */
        arm_test_reg_imm8(unroll->out, ARM_CMP, reg, 0);
        patch = unroll->out;
        arm_branch_imm(unroll->out, ARM_CC_NE, 0);

        /* Re-execute the current instruction in the interpreter */
        if(popReg)
        {
                --(unroll->pseudoStackSize);
                ReExecute(unroll, pc, label);
                ++(unroll->pseudoStackSize);
        }
        else
        {
                ReExecute(unroll, pc, label);
        }

        /* Continue with real execution here */
        arm_patch(patch, unroll->out);
}

/*
 * Check an array access operation for exception conditions.
 * Upon successful execution, "reg" will point at the start
 * of the array contents.
 */
static void CheckArrayAccess(ARMUnroll *unroll, int reg, int reg2,
                                                         unsigned char *pc, 
unsigned char *label)
{
        arm_inst_ptr patch1;
        arm_inst_ptr patch2;

        /* Check the array reference against NULL */
        arm_test_reg_imm8(unroll->out, ARM_CMP, reg, 0);
        patch1 = unroll->out;
        arm_branch_imm(unroll->out, ARM_CC_EQ, 0);

        /* Check the array bounds */
        arm_load_advance(unroll->out, ARM_WORK, reg);
        arm_test_reg_reg(unroll->out, ARM_CMP, reg2, ARM_WORK);
        patch2 = unroll->out;
        arm_branch_imm(unroll->out, ARM_CC_LT_UN, 0);

        /* Re-execute the current instruction in the interpreter */
        arm_patch(patch1, unroll->out);
        ReExecute(unroll, pc, label);

        /* Continue with real execution here */
        arm_patch(patch2, unroll->out);
}

/*
 * Check a 2D array access operation for exception conditions.
 */
static void Check2DArrayAccess(ARMUnroll *unroll, int reg, int reg2, int reg3,
                                                           unsigned char *pc, 
unsigned char *label)
{
        arm_inst_ptr patch1;
        arm_inst_ptr patch2;
        arm_inst_ptr patch3;

        /* Check the array reference against NULL */
        arm_test_reg_imm8(unroll->out, ARM_CMP, reg, 0);
        patch1 = unroll->out;
        arm_branch_imm(unroll->out, ARM_CC_EQ, 0);

        /* Check the array bounds.  We assume that we can use the link
           register as a work register because "lr" would have been
           saved on entry to "_ILCVMInterpreter" */
        arm_load_membase(unroll->out, ARM_WORK, reg, 12);
        arm_alu_reg_reg(unroll->out, ARM_SUB, reg2, reg2, ARM_WORK);
        arm_load_membase(unroll->out, ARM_LINK, reg, 16);
        arm_test_reg_reg(unroll->out, ARM_CMP, reg2, ARM_LINK);
        patch2 = unroll->out;
        arm_branch_imm(unroll->out, ARM_CC_LT_UN, 0);
        arm_alu_reg_reg(unroll->out, ARM_ADD, reg2, reg2, ARM_WORK);
        patch3 = unroll->out;
        arm_jump_imm(unroll->out, 0);
        arm_patch(patch2, unroll->out);
        arm_load_membase(unroll->out, ARM_WORK, reg, 24);
        arm_alu_reg_reg(unroll->out, ARM_SUB, reg3, reg3, ARM_WORK);
        arm_load_membase(unroll->out, ARM_LINK, reg, 28);
        arm_test_reg_reg(unroll->out, ARM_CMP, reg3, ARM_LINK);
        patch2 = unroll->out;
        arm_branch_imm(unroll->out, ARM_CC_LT_UN, 0);
        arm_alu_reg_reg(unroll->out, ARM_ADD, reg3, reg3, ARM_WORK);
        arm_load_membase(unroll->out, ARM_WORK, reg, 12);
        arm_alu_reg_reg(unroll->out, ARM_ADD, reg2, reg2, ARM_WORK);

        /* Re-execute the current instruction in the interpreter */
        arm_patch(patch1, unroll->out);
        arm_patch(patch3, unroll->out);
        ReExecute(unroll, pc, label);

        /* Compute the address of the array element */
        arm_patch(patch2, unroll->out);
        arm_load_membase(unroll->out, ARM_WORK, reg, 20);
        arm_mul_reg_reg(unroll->out, reg2, reg2, ARM_WORK);
        arm_load_membase(unroll->out, ARM_WORK, reg, 32);
        arm_mul_reg_reg(unroll->out, reg3, reg3, ARM_WORK);
        arm_alu_reg_reg(unroll->out, ARM_ADD, reg2, reg2, reg3);
        arm_load_membase(unroll->out, ARM_WORK, reg, 4);
        arm_mul_reg_reg(unroll->out, reg2, reg2, ARM_WORK);
        arm_load_membase(unroll->out, reg, reg, 8);
        arm_alu_reg_reg(unroll->out, ARM_ADD, reg, reg, reg2);
}

#elif defined(IL_UNROLL_CASES)

case COP_BREAD:
{
        /* Read a signed byte value from a pointer */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_load_membase_sbyte(unroll.out, reg, reg, 0);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_UBREAD:
{
        /* Read an unsigned byte value from a pointer */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_load_membase_byte(unroll.out, reg, reg, 0);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_SREAD:
{
        /* Read a signed short value from a pointer */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_load_membase_short(unroll.out, reg, reg, 0);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_USREAD:
{
        /* Read an unsigned short value from a pointer */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_load_membase_ushort(unroll.out, reg, reg, 0);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_IREAD:
case COP_PREAD:
{
        /* Read a word value from a pointer */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_load_membase(unroll.out, reg, reg, 0);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_BWRITE:
{
        /* Write a byte value to a pointer */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_store_membase_byte(unroll.out, reg2, reg, 0);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_SWRITE:
{
        /* Write a short value to a pointer */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_store_membase_short(unroll.out, reg2, reg, 0);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_IWRITE:
case COP_PWRITE:
{
        /* Write a word value to a pointer */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_store_membase(unroll.out, reg2, reg, 0);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_BWRITE_R:
{
        /* Write a byte value to a pointer with reversed arguments */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_store_membase_byte(unroll.out, reg, reg2, 0);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_SWRITE_R:
{
        /* Write a short value to a pointer with reversed arguments */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_store_membase_short(unroll.out, reg, reg2, 0);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_IWRITE_R:
case COP_PWRITE_R:
{
        /* Write a word value to a pointer with reversed arguments */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_store_membase(unroll.out, reg, reg2, 0);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_PADD_OFFSET:
{
        /* Add an offset value to a pointer */
        unsigned val = (unsigned)CVM_ARG_BYTE;
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_alu_reg_imm(unroll.out, ARM_ADD, reg, reg, val);
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case COP_PADD_I4:
case COP_PADD_I4_R:
{
        /* Add an integer value to a pointer */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_alu_reg_reg(unroll.out, ARM_ADD, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_PSUB:
case COP_PSUB_I4:
{
        /* Subtract pointers, or subtract an integer from a pointer */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        arm_alu_reg_reg(unroll.out, ARM_SUB, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_BREAD_ELEM:
{
        /* Read a byte from an array */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        CheckArrayAccess(&unroll, reg, reg2, pc, (unsigned char *)inst);
        arm_load_memindex_sbyte(unroll.out, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_UBREAD_ELEM:
{
        /* Read an unsigned byte from an array */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        CheckArrayAccess(&unroll, reg, reg2, pc, (unsigned char *)inst);
        arm_load_memindex_byte(unroll.out, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_SREAD_ELEM:
{
        /* Read a short from an array */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        CheckArrayAccess(&unroll, reg, reg2, pc, (unsigned char *)inst);
        arm_load_memindex_short(unroll.out, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_USREAD_ELEM:
{
        /* Read an unsigned short from an array */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        CheckArrayAccess(&unroll, reg, reg2, pc, (unsigned char *)inst);
        arm_load_memindex_ushort(unroll.out, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_IREAD_ELEM:
case COP_PREAD_ELEM:
{
        /* Read a word from an array */
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        CheckArrayAccess(&unroll, reg, reg2, pc, (unsigned char *)inst);
        arm_load_memindex(unroll.out, reg, reg, reg2);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_BWRITE_ELEM:
{
        /* Write a byte to an array */
        UNROLL_START();
        GetTopThreeWordRegisters(&unroll, &reg, &reg2, &reg3);
        CheckArrayAccess(&unroll, reg, reg2, pc, (unsigned char *)inst);
        arm_store_memindex_byte(unroll.out, reg3, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_SWRITE_ELEM:
{
        /* Write a short to an array */
        UNROLL_START();
        GetTopThreeWordRegisters(&unroll, &reg, &reg2, &reg3);
        CheckArrayAccess(&unroll, reg, reg2, pc, (unsigned char *)inst);
        arm_store_memindex_short(unroll.out, reg3, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_IWRITE_ELEM:
case COP_PWRITE_ELEM:
{
        /* Write a word to an array */
        UNROLL_START();
        GetTopThreeWordRegisters(&unroll, &reg, &reg2, &reg3);
        CheckArrayAccess(&unroll, reg, reg2, pc, (unsigned char *)inst);
        arm_store_memindex(unroll.out, reg3, reg, reg2);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_ARRAY_LEN:
{
        /* Get the length of an array */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        CheckForNull(&unroll, reg, pc, (unsigned char *)inst, 0);
        arm_load_membase(unroll.out, reg, reg, 0);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_BREAD_FIELD:
{
        /* Read a byte field from an object */
        unsigned temp = (unsigned)CVM_ARG_BYTE;
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        CheckForNull(&unroll, reg, pc, (unsigned char *)inst, 0);
        arm_load_membase_sbyte(unroll.out, reg, reg, (int)temp);
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case COP_UBREAD_FIELD:
{
        /* Read an unsigned byte field from an object */
        unsigned temp = (unsigned)CVM_ARG_BYTE;
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        CheckForNull(&unroll, reg, pc, (unsigned char *)inst, 0);
        arm_load_membase_byte(unroll.out, reg, reg, (int)temp);
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case COP_SREAD_FIELD:
{
        /* Read a short field from an object */
        unsigned temp = (unsigned)CVM_ARG_BYTE;
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        CheckForNull(&unroll, reg, pc, (unsigned char *)inst, 0);
        arm_load_membase_short(unroll.out, reg, reg, (int)temp);
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case COP_USREAD_FIELD:
{
        /* Read an unsigned byte field from an object */
        unsigned temp = (unsigned)CVM_ARG_BYTE;
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        CheckForNull(&unroll, reg, pc, (unsigned char *)inst, 0);
        arm_load_membase_ushort(unroll.out, reg, reg, (int)temp);
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case COP_IREAD_FIELD:
case COP_PREAD_FIELD:
{
        /* Read a word field from an object */
        unsigned temp = (unsigned)CVM_ARG_BYTE;
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        CheckForNull(&unroll, reg, pc, (unsigned char *)inst, 0);
        arm_load_membase(unroll.out, reg, reg, (int)temp);
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case COP_BWRITE_FIELD:
{
        /* Write a byte field to an object */
        unsigned temp = (unsigned)CVM_ARG_BYTE;
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        CheckForNull(&unroll, reg, pc, (unsigned char *)inst, 0);
        arm_store_membase_byte(unroll.out, reg2, reg, (int)temp);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case COP_SWRITE_FIELD:
{
        /* Write a short field to an object */
        unsigned temp = (unsigned)CVM_ARG_BYTE;
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        CheckForNull(&unroll, reg, pc, (unsigned char *)inst, 0);
        arm_store_membase_short(unroll.out, reg2, reg, (int)temp);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case COP_IWRITE_FIELD:
case COP_PWRITE_FIELD:
{
        /* Write a word field to an object */
        unsigned temp = (unsigned)CVM_ARG_BYTE;
        UNROLL_START();
        GetTopTwoWordRegisters(&unroll, &reg, &reg2);
        CheckForNull(&unroll, reg, pc, (unsigned char *)inst, 0);
        arm_store_membase(unroll.out, reg2, reg, (int)temp);
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case COP_IREAD_THIS:
case COP_PREAD_THIS:
{
        /* Read a word field from the "this" object */
        unsigned temp = (unsigned)CVM_ARG_BYTE;
        UNROLL_START();

        /* Load "this" into a new register */
        reg = GetWordRegister(&unroll);
        arm_load_membase(unroll.out, reg, REG_FRAME, 0);

        /* Check "this" for NULL if we haven't done so already.
           If "thisValidated" is -1, then it indicates that the
           "this" variable has been addressed using "waddr" and
           so we must always validate it just in case someone
           writes to that address further down the code */
        if(unroll.thisValidated <= 0)
        {
                CheckForNull(&unroll, reg, pc, (unsigned char *)inst, 1);
                if(!(unroll.thisValidated))
                {
                        unroll.thisValidated = 1;
                }
        }

        /* Read the contents of the field */
        arm_load_membase(unroll.out, reg, reg, (int)temp);
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case 0x100 + COP_PREFIX_GET2D:
{
        /* Get the array object reference and indices into registers */
        UNROLL_START();
        GetTopThreeWordRegisters(&unroll, &reg, &reg2, &reg3);

        /* Check the access and compute the element address */
        Check2DArrayAccess(&unroll, reg, reg2, reg3, pc, (unsigned char *)inst);

        /* Pop unnecessary registers: the address is now in "reg" */
        FreeTopRegister(&unroll, -1);
        FreeTopRegister(&unroll, -1);

        /* Skip to the next instruction */
        MODIFY_UNROLL_PC(CVMP_LEN_NONE);
}
break;

case 0x100 + COP_PREFIX_SET2D:
{
        unsigned temp = (unsigned)CVMP_ARG_WORD;
        int offset;

        /* Flush the register stack onto the real stack so that we know
           where everything is */
        UNROLL_START();
        FlushRegisterStack(&unroll);
        offset = unroll.stackHeight - ((int)((temp + 3) * 4));

        /* Fetch the array object reference and indices */
        reg = regAllocOrder[0];
        reg2 = regAllocOrder[1];
        reg3 = regAllocOrder[2];
        arm_load_membase(unroll.out, reg, REG_STACK, offset);
        arm_load_membase(unroll.out, reg2, REG_STACK, offset + 4);
        arm_load_membase(unroll.out, reg3, REG_STACK, offset + 8);

        /* Check the access and compute the element address */
        Check2DArrayAccess(&unroll, reg, reg2, reg3, pc, (unsigned char *)inst);

        /* Shift everything down on the stack to squash out the indices */
        arm_store_membase(unroll.out, reg, REG_STACK, offset);
        while(temp > 0)
        {
                offset += 4;
                arm_load_membase(unroll.out, reg2, REG_STACK, offset + 8);
                arm_store_membase(unroll.out, reg2, REG_STACK, offset);
                --temp;
        }

        /* Adjust the top of stack pointer */
        unroll.stackHeight -= 8;

        /* Skip to the next instruction */
        MODIFY_UNROLL_PC(CVMP_LEN_WORD);
}
break;

#endif /* IL_UNROLL_CASES */

--- NEW FILE ---
/*
 * unroll_arm_var.c - Variable handling for ARM CVM unrolling.
 *
 * Copyright (C) 2003  Southern Storm Software, Pty Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifdef IL_UNROLL_CASES

case COP_ILOAD_0:
case COP_PLOAD_0:
{
        /* Unroll an access to frame variable 0 */
        UNROLL_START();
        reg = GetCachedWordRegister(&unroll, 0);
        if(reg != -1)
        {
                arm_load_membase(unroll.out, reg, REG_FRAME, 0);
        }
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_ILOAD_1:
case COP_PLOAD_1:
{
        /* Unroll an access to frame variable 1 */
        UNROLL_START();
        reg = GetCachedWordRegister(&unroll, 1);
        if(reg != -1)
        {
                arm_load_membase(unroll.out, reg, REG_FRAME, 4);
        }
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_ILOAD_2:
case COP_PLOAD_2:
{
        /* Unroll an access to frame variable 2 */
        UNROLL_START();
        reg = GetCachedWordRegister(&unroll, 2);
        if(reg != -1)
        {
                arm_load_membase(unroll.out, reg, REG_FRAME, 8);
        }
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_ILOAD_3:
case COP_PLOAD_3:
{
        /* Unroll an access to frame variable 3 */
        UNROLL_START();
        reg = GetCachedWordRegister(&unroll, 3);
        if(reg != -1)
        {
                arm_load_membase(unroll.out, reg, REG_FRAME, 12);
        }
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_ILOAD:
case COP_PLOAD:
{
        /* Unroll an access to an arbitrary frame variable */
        unsigned temp = CVM_ARG_WIDE_SMALL;
        UNROLL_START();
        reg = GetCachedWordRegister(&unroll, temp);
        if(reg != -1)
        {
                arm_load_membase(unroll.out, reg, REG_FRAME, temp * 4);
        }
        MODIFY_UNROLL_PC(CVM_LEN_WIDE_SMALL);
}
break;

case COP_BLOAD:
{
        /* Unroll an access to a byte frame variable */
        unsigned temp = CVM_ARG_BYTE;
        UNROLL_START();
        reg = GetCachedWordRegister(&unroll, temp);
        if(reg != -1)
        {
                arm_load_membase_byte(unroll.out, reg, REG_FRAME, temp * 4);
        }
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case COP_ISTORE_0:
case COP_PSTORE_0:
{
        /* Unroll a store to frame variable 0 */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_store_membase(unroll.out, reg, REG_FRAME, 0);
        FreeTopRegister(&unroll, 0);
        if(unroll.thisValidated > 0)
        {
                /* The "this" variable must be re-validated */
                unroll.thisValidated = 0;
        }
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_ISTORE_1:
case COP_PSTORE_1:
{
        /* Unroll a store to frame variable 1 */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_store_membase(unroll.out, reg, REG_FRAME, 4);
        FreeTopRegister(&unroll, 1);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_ISTORE_2:
case COP_PSTORE_2:
{
        /* Unroll a store to frame variable 2 */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_store_membase(unroll.out, reg, REG_FRAME, 8);
        FreeTopRegister(&unroll, 2);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_ISTORE_3:
case COP_PSTORE_3:
{
        /* Unroll a store to frame variable 3 */
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_store_membase(unroll.out, reg, REG_FRAME, 12);
        FreeTopRegister(&unroll, 3);
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_ISTORE:
case COP_PSTORE:
{
        /* Unroll a store to an arbitrary frame variable */
        unsigned temp = CVM_ARG_WIDE_SMALL;
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_store_membase(unroll.out, reg, REG_FRAME, temp * 4);
        FreeTopRegister(&unroll, temp);
        if(temp == 0 && unroll.thisValidated > 0)
        {
                /* The "this" variable must be re-validated */
                unroll.thisValidated = 0;
        }
        MODIFY_UNROLL_PC(CVM_LEN_WIDE_SMALL);
}
break;

case COP_BSTORE:
{
        /* Unroll a store to a byte frame variable */
        unsigned temp = CVM_ARG_BYTE;
        UNROLL_START();
        reg = GetTopWordRegister(&unroll);
        arm_store_membase_byte(unroll.out, reg, REG_FRAME, temp * 4);
        FreeTopRegister(&unroll, temp);
        MODIFY_UNROLL_PC(CVM_LEN_BYTE);
}
break;

case COP_WADDR:
{
        /* Get the address of a frame word */
        unsigned temp = CVM_ARG_WIDE_SMALL;
        UNROLL_START();
        reg = GetWordRegister(&unroll);
        arm_mov_reg_reg(unroll.out, reg, REG_FRAME);
        if(temp != 0)
        {
                arm_alu_reg_imm(unroll.out, ARM_ADD, reg, reg, temp * 4);
        }
        else
        {
                /* We don't know if someone might write to this address,
                   so we have to assume that "this" will need to be
                   validated always from now on */
                unroll.thisValidated = -1;
        }
        MODIFY_UNROLL_PC(CVM_LEN_WIDE_SMALL);
}
break;

case COP_MK_LOCAL_1:
{
        /* Make a single local variable word */
        UNROLL_START();
        FlushRegisterStack(&unroll);
        arm_mov_reg_imm8(unroll.out, ARM_WORK, 0);
        arm_store_membase(unroll.out, ARM_WORK, REG_STACK, unroll.stackHeight);
        unroll.stackHeight += 4;
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_MK_LOCAL_2:
{
        /* Make two local variable words */
        UNROLL_START();
        FlushRegisterStack(&unroll);
        arm_mov_reg_imm8(unroll.out, ARM_WORK, 0);
        arm_store_membase(unroll.out, ARM_WORK, REG_STACK, unroll.stackHeight);
        arm_store_membase(unroll.out, ARM_WORK, REG_STACK, unroll.stackHeight + 
4);
        unroll.stackHeight += 8;
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_MK_LOCAL_3:
{
        /* Make three local variable words */
        UNROLL_START();
        FlushRegisterStack(&unroll);
        arm_mov_reg_imm8(unroll.out, ARM_WORK, 0);
        arm_store_membase(unroll.out, ARM_WORK, REG_STACK, unroll.stackHeight);
        arm_store_membase(unroll.out, ARM_WORK, REG_STACK, unroll.stackHeight + 
4);
        arm_store_membase(unroll.out, ARM_WORK, REG_STACK, unroll.stackHeight + 
8);
        unroll.stackHeight += 12;
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_DUP:
{
        /* Duplicate the top word on the stack */
        UNROLL_START();
        reg = PeekTopWordRegister(&unroll);
        if(reg != -1)
        {
                /* The top is already in a register, so move it to a new 
register */
                reg2 = GetWordRegister(&unroll);
                if(unroll.pseudoStackSize > 1)
                {
                        arm_mov_reg_reg(unroll.out, reg2, reg);
                }
                else
                {
                        /* "GetWordRegister" flushed all registers, so the value
                           we want to duplicate is now on the CVM stack */
                        arm_load_membase(unroll.out, reg2, REG_STACK,
                                                         unroll.stackHeight - 
4);
                }
        }
        else
        {
                /* The top is on the CVM stack */
                reg = GetWordRegister(&unroll);
                arm_load_membase(unroll.out, reg, REG_STACK, unroll.stackHeight 
- 4);
        }
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

case COP_POP:
{
        /* Pop the top word on the stack */
        UNROLL_START();
        reg = PeekTopWordRegister(&unroll);
        if(reg != -1)
        {
                /* Abandon the register's contents */
                FreeTopRegister(&unroll, -1);
        }
        else
        {
                /* Flush the register stack and then decrease its height */
                FlushRegisterStack(&unroll);
                unroll.stackHeight -= 4;
        }
        MODIFY_UNROLL_PC(CVM_LEN_NONE);
}
break;

#endif /* IL_UNROLL_CASES */

Index: Makefile.am
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/engine/Makefile.am,v
retrieving revision 1.57
retrieving revision 1.58
diff -C2 -r1.57 -r1.58
*** Makefile.am 5 Feb 2003 09:51:31 -0000       1.57
--- Makefile.am 4 May 2003 21:45:34 -0000       1.58
***************
*** 51,54 ****
--- 51,55 ----
                                                throw.c \
                                                unroll_x86.c \
+                                               unroll_arm.c \
                                                verify.c
  

Index: cvm.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/engine/cvm.c,v
retrieving revision 1.40
retrieving revision 1.41
diff -C2 -r1.40 -r1.41
*** cvm.c       9 Dec 2002 08:59:00 -0000       1.40
--- cvm.c       4 May 2003 21:45:34 -0000       1.41
***************
*** 81,84 ****
--- 81,93 ----
                return ILMemCmp(dst, src, len);
        }
+ #elif defined(CVM_ARM) && defined(__GNUC__) && !defined(IL_NO_ASM)
+     #define REGISTER_ASM_PC(x)              register x asm ("r4")
+     #define REGISTER_ASM_STACK(x)           register x asm ("r5")
+     #define REGISTER_ASM_FRAME(x)           register x asm ("r6")
+       #define IL_MEMCPY(dst,src,len)                  (ILMemCpy((dst), (src), 
(len)))
+       #define IL_MEMMOVE(dst,src,len)                 (ILMemMove((dst), 
(src), (len)))
+       #define IL_MEMZERO(dst,len)                             
(ILMemZero((dst), (len)))
+       #define IL_MEMSET(dst,ch,len)                   (ILMemSet((dst), (ch), 
(len)))
+       #define IL_MEMCMP(dst,src,len)                  (ILMemCmp((dst), (src), 
(len)))
  #else
      #define REGISTER_ASM_PC(x)              x

Index: cvm_config.h
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/engine/cvm_config.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -r1.5 -r1.6
*** cvm_config.h        10 Jun 2002 05:39:26 -0000      1.5
--- cvm_config.h        4 May 2003 21:45:34 -0000       1.6
***************
*** 83,86 ****
--- 83,91 ----
        #define CVM_WORDS_AND_PTRS_SAME_SIZE
  #endif
+ #if defined(__arm) || defined(__arm__)
+       #define CVM_ARM
+       #define CVM_LONGS_ALIGNED_WORD
+       #define CVM_WORDS_AND_PTRS_SAME_SIZE
+ #endif
  
  /*
***************
*** 175,178 ****
--- 180,191 ----
        defined(IL_CONFIG_UNROLL)
  #define       IL_CVM_DIRECT_UNROLLED_X86
+ #define       IL_CVM_DIRECT_UNROLLED
+ #endif
+ #if defined(IL_CVM_DIRECT) && defined(CVM_ARM) && \
+       defined(__GNUC__) && !defined(IL_NO_ASM) && \
+       !defined(IL_CVM_PROFILE_CVM_METHODS) && \
+       !defined(IL_CVM_PROFILE_CVM_VAR_USAGE) && \
+       defined(IL_CONFIG_UNROLL)
+ #define       IL_CVM_DIRECT_UNROLLED_ARM
  #define       IL_CVM_DIRECT_UNROLLED
  #endif

Index: unroll_x86.c
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnet/engine/unroll_x86.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -C2 -r1.11 -r1.12
*** unroll_x86.c        24 Jun 2002 02:20:32 -0000      1.11
--- unroll_x86.c        4 May 2003 21:45:34 -0000       1.12
***************
*** 1214,1218 ****
  }
  
! #else /* !IL_CVM_DIRECT_UNROLLED_X86 */
  
  /*
--- 1214,1220 ----
  }
  
! #endif /* IL_CVM_DIRECT_UNROLLED_X86 */
! 
! #ifndef IL_CVM_DIRECT_UNROLLED
  
  /*
***************
*** 1235,1239 ****
  }
  
! #endif /* !IL_CVM_DIRECT_UNROLLED_X86 */
  
  #ifdef        __cplusplus
--- 1237,1241 ----
  }
  
! #endif /* !IL_CVM_DIRECT_UNROLLED */
  
  #ifdef        __cplusplus





reply via email to

[Prev in Thread] Current Thread [Next in Thread]