📄 jitemitter_cpu.c
字号:
/* * @(#)jitemitter_cpu.c 1.263 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * 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 version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * *//* * ARM-specific bits. * Does not use compiler context, yet. */#include "javavm/include/defs.h"#include "javavm/include/objects.h"#include "javavm/include/utils.h"#include "javavm/include/globals.h"#include "javavm/include/interpreter.h"#include "javavm/include/ccm_runtime.h"#include "javavm/include/ccee.h"#include "javavm/include/jit/jit.h"#include "javavm/include/jit/jitcontext.h"#include "javavm/include/jit/jitutils.h"#include "javavm/include/jit/jitmemory.h"#include "javavm/include/jit/jitstats.h"#include "javavm/include/jit/jitcomments.h"#include "javavm/include/jit/jitirnode.h"#include "portlibs/jit/risc/include/porting/jitriscemitter.h"#include "portlibs/jit/risc/include/porting/ccmrisc.h"#include "portlibs/jit/risc/include/export/jitregman.h"#include "javavm/include/jit/jitconstantpool.h"#include "javavm/include/jit/jitcodebuffer.h"#include "javavm/include/jit/jitintrinsic.h"#include "javavm/include/jit/jitpcmap.h"#include "javavm/include/jit/jitfixup.h"#include "javavm/include/porting/endianness.h"#include "javavm/include/porting/doubleword.h"#include "javavm/include/porting/jit/jit.h"#include "javavm/include/clib.h"/* * Macros for 64-bit access. */#if CVM_ENDIANNESS == CVM_BIG_ENDIAN#define HIREG(reg) (reg)#define LOREG(reg) (reg)+1#elif CVM_ENDIANNESS == CVM_LITTLE_ENDIAN#define HIREG(reg) (reg)+1#define LOREG(reg) (reg)#endifstatic voidCVMARMemitCompareConditional(CVMJITCompilationContext* con, int opcode, int lhsRegID, CVMCPUALURhsToken rhsToken, CVMCPUCondCode condCode);/************************************************************** * CPU ALURhs and associated types - The following are implementations * of the functions for the ALURhs abstraction required by the RISC * emitter porting layer. **************************************************************//* ALURhs constructors and query APIs: ==================================== *//* Purpose: Constructs a constant type CVMCPUALURhs. */CVMCPUALURhs*CVMCPUalurhsNewConstant(CVMJITCompilationContext* con, CVMInt32 v){ CVMCPUALURhs* ap = CVMJITmemNew(con, JIT_ALLOC_CGEN_ALURHS, sizeof(CVMCPUALURhs)); ap->type = CVMARM_ALURHS_CONSTANT; ap->constValue = v; return ap;}/* Purpose: Constructs an ALURhs to represent a register shifted by a constant. */CVMCPUALURhs*CVMARMalurhsNewShiftByConstant( CVMJITCompilationContext* con, int shiftOp, CVMRMResource* reg, CVMInt32 shiftval){ CVMCPUALURhs* ap = CVMJITmemNew(con, JIT_ALLOC_CGEN_ALURHS, sizeof(CVMCPUALURhs)); ap->type = CVMARM_ALURHS_SHIFT_BY_CONSTANT; ap->shiftOp = shiftOp; ap->constValue = shiftval; ap->r1 = reg; return ap;}/* Purpose: Constructs an ALURhs to represent a register shifted by another register. */CVMCPUALURhs*CVMARMalurhsNewShiftByReg( CVMJITCompilationContext* con, int shiftOp, CVMRMResource* reg, CVMRMResource* shiftval){ CVMCPUALURhs* ap = CVMJITmemNew(con, JIT_ALLOC_CGEN_ALURHS, sizeof(CVMCPUALURhs)); ap->type = CVMARM_ALURHS_SHIFT_BY_REGISTER; ap->shiftOp = shiftOp; ap->r1 = reg; ap->r2 = shiftval; return ap;}/* ALURhs token encoder APIs: ============================================= */#define CVMARMalurhsEncodeLargeConstantToken(base, rotate) \ (CVMARM_MODE1_CONSTANT | (rotate << 8) | base)/* Purpose: Encodes the token for the CVMCPUALURhs operand for use in the instruction emitters. */CVMCPUALURhsTokenCVMARMalurhsEncodeToken(CVMJITCompilationContext* con, CVMARMALURhsType type, int constValue, int shiftOp, int r1RegID, int r2RegID){ CVMJITcsPushSourceRegister(con, r1RegID); switch(type){ case CVMARM_ALURHS_CONSTANT: { CVMUint32 base; CVMUint32 rotate; CVMBool success; success = CVMARMmode1EncodeImmediate(constValue, &base, &rotate); CVMassert(success); return CVMARM_MODE1_CONSTANT | (rotate << 8) | base; } case CVMARM_ALURHS_SHIFT_BY_CONSTANT: { /* Currently, CVMARM_ALURHS_SHIFT_BY_CONSTANT is only used for implementing the Java shift operators. Hence, the shift offsets must be between 0 and 31 (and were masked with 0x1f before getting here). NOTE: For CVMCPU_SRL_OPCODE and CVMCPU_SRA_OPCODE, a shiftOffset of 32 is encoded as 0. Hence, if the shiftOffset is meant to be 0, then the shiftop will have to be set to CVMCPU_SLL_OPCODE which essentially does nothing as expected. */ CVMassert((constValue >= 0) && (constValue <= 31)); shiftOp = (constValue == 0) ? CVMCPU_SLL_OPCODE : shiftOp; return CVMARM_MODE1_SHIFT_CONSTANT | r1RegID | shiftOp | constValue << 7; } case CVMARM_ALURHS_SHIFT_BY_REGISTER: CVMJITcsPushSourceRegister(con, r2RegID); return CVMARM_MODE1_SHIFT_REGISTER | r1RegID | shiftOp | r2RegID << 8; default: CVMassert(CVM_FALSE); return 0; }}/* Purpose: Gets the token for the CVMCPUALURhs operand for use in the instruction emitters. */CVMCPUALURhsTokenCVMARMalurhsGetToken(CVMJITCompilationContext* con, const CVMCPUALURhs *aluRhs){ CVMCPUALURhsToken result; int r1RegID = CVMCPU_INVALID_REG; int r2RegID = CVMCPU_INVALID_REG; if (aluRhs->type == CVMARM_ALURHS_SHIFT_BY_CONSTANT) { r1RegID = CVMRMgetRegisterNumber(aluRhs->r1); } else if (aluRhs->type == CVMARM_ALURHS_SHIFT_BY_REGISTER) { r1RegID = CVMRMgetRegisterNumber(aluRhs->r1); r2RegID = CVMRMgetRegisterNumber(aluRhs->r2); } result = CVMARMalurhsEncodeToken(con, aluRhs->type, aluRhs->constValue, aluRhs->shiftOp, r1RegID, r2RegID); return result;}/* ALURhs resource management APIs: ======================================= *//* Purpose: Pins the resources that this CVMCPUALURhs may use. */voidCVMCPUalurhsPinResource(CVMJITRMContext* con, int opcode, CVMCPUALURhs* ap, CVMRMregset target, CVMRMregset avoid){ switch (ap->type){ case CVMARM_ALURHS_CONSTANT: /* If we can't encode the constant as an immediate, then load it into a register and re-write the aluRhs as a CVMARM_ALURHS_SHIFT_BY_CONSTANT: */ if (!CVMCPUalurhsIsEncodableAsImmediate(opcode, ap->constValue)) { ap->type = CVMARM_ALURHS_SHIFT_BY_CONSTANT; ap->shiftOp = CVMARM_NOSHIFT_OPCODE; ap->r1 = CVMRMgetResourceForConstant32(con, target, avoid, ap->constValue); ap->constValue = 0; } return; case CVMARM_ALURHS_SHIFT_BY_CONSTANT: CVMRMpinResource(con, ap->r1, target, avoid); return; case CVMARM_ALURHS_SHIFT_BY_REGISTER: CVMRMpinResource(con, ap->r1, target, avoid); CVMRMpinResource(con, ap->r2, target, avoid); return; }}/* Purpose: Relinquishes the resources that this CVMCPUALURhsToken may use. */voidCVMCPUalurhsRelinquishResource(CVMJITRMContext* con, CVMCPUALURhs* ap){ switch (ap->type){ case CVMARM_ALURHS_CONSTANT: break; case CVMARM_ALURHS_SHIFT_BY_CONSTANT: CVMRMrelinquishResource(con, ap->r1); break; case CVMARM_ALURHS_SHIFT_BY_REGISTER: CVMRMrelinquishResource(con, ap->r1); CVMRMrelinquishResource(con, ap->r2); break; } /* Will be freed whole-sale at the very end free(ap); */}/* MemSpec constructors and query APIs: =================================== *//* Purpose: Constructs a CVMCPUMemSpec immediate operand. */CVMCPUMemSpec *CVMCPUmemspecNewImmediate(CVMJITCompilationContext *con, CVMInt32 value){ CVMCPUMemSpec *mp; mp = CVMJITmemNew(con, JIT_ALLOC_CGEN_MEMSPEC, sizeof(CVMCPUMemSpec)); mp->type = CVMCPU_MEMSPEC_IMMEDIATE_OFFSET; mp->offsetValue = value; mp->offsetReg = NULL; mp->shiftOpcode = CVMARM_NOSHIFT_OPCODE; mp->shiftAmount = 0; return mp;}/* Purpose: Constructs a MemSpec register operand. */CVMCPUMemSpec *CVMCPUmemspecNewRegister(CVMJITCompilationContext *con, CVMBool offsetIsToBeAdded, CVMRMResource *offsetReg){ CVMCPUMemSpec *mp; mp = CVMJITmemNew(con, JIT_ALLOC_CGEN_MEMSPEC, sizeof(CVMCPUMemSpec)); mp->type = CVMCPU_MEMSPEC_REG_OFFSET; mp->offsetValue = 0; mp->offsetReg = offsetReg; mp->shiftOpcode = CVMARM_NOSHIFT_OPCODE; mp->shiftAmount = 0; return mp;}/* MemSpec token encoder APIs: ============================================ */#define CVMARMmemspecGetTokenType(memSpecToken) \ ((memSpecToken) & 0xff)#define CVMARMmemspecGetTokenOffset(memSpecToken) \ ((CVMInt32)((CVMInt16)(((memSpecToken) >> 16) & 0xffff)))#define CVMARMmemspecGetTokenShiftOpcode(memSpecToken) \ (((memSpecToken) >> 8) & 0x60)#define CVMARMmemspecGetTokenShiftAmount(memSpecToken) \ (((memSpecToken) >> 8) & 0x1f)/* Purpose: Encodes a CVMCPUMemSpecToken from the specified memSpec. */CVMCPUMemSpecTokenCVMARMmemspecGetToken(CVMJITCompilationContext *con, const CVMCPUMemSpec *memSpec){ CVMCPUMemSpecToken token; int type = memSpec->type; int offset; int shiftOp = memSpec->shiftOpcode; int shiftImm = memSpec->shiftAmount; offset = (type == CVMCPU_MEMSPEC_REG_OFFSET) ? CVMRMgetRegisterNumber(memSpec->offsetReg) : memSpec->offsetValue; token = CVMARMmemspecEncodeToken(type, offset, shiftOp, shiftImm); return token;}/* MemSpec resource management APIs: ====================================== *//* Purpose: Pins the resources that this CVMCPUMemSpec may use. */voidCVMCPUmemspecPinResource(CVMJITRMContext *con, CVMCPUMemSpec *self, CVMRMregset target, CVMRMregset avoid){ switch (self->type) { case CVMCPU_MEMSPEC_IMMEDIATE_OFFSET: /* If we can't encode the constant as an immediate, then load it into a register and re-write the memSpec as a CVMCPU_MEMSPEC_REG_OFFSET: */ if (!CVMCPUmemspecIsEncodableAsImmediate(self->offsetValue)) { self->type = CVMCPU_MEMSPEC_REG_OFFSET; self->offsetReg = CVMRMgetResourceForConstant32(con, target, avoid, self->offsetValue); self->offsetValue = 0; self->shiftOpcode = CVMARM_NOSHIFT_OPCODE; self->shiftAmount = 0; } return; case CVMCPU_MEMSPEC_REG_OFFSET: CVMRMpinResource(con, self->offsetReg, target, avoid); return; default: /* No pinning needed for the other memSpec types. */ /* Since the post-increment and pre-decrement types are only used for pushing and popping arguments on to the Java stack, the immediate offset should always be small. No need to check if it is encodable: */ CVMassert(CVMCPUmemspecIsEncodableAsImmediate(self->offsetValue)); }}/* Purpose: Relinquishes the resources that this CVMCPUMemSpec may use. */voidCVMCPUmemspecRelinquishResource(CVMJITRMContext *con, CVMCPUMemSpec *self){ switch (self->type) { case CVMCPU_MEMSPEC_REG_OFFSET: CVMRMrelinquishResource(con, self->offsetReg); break; default: ; /* No unpinning needed for the other memSpec types. */ }}/************************************************************** * CPU code emitters - The following are implementations of code * emitters required by the RISC emitter porting layer. **************************************************************//* Private ARM specific defintions: ======================================= */#define ARM_MVN_OPCODE (0x1e << 20)#define ARM_ADC_OPCODE (0x0a << 20) /* needed for ADD64 codegen comments */#define ARM_SBC_OPCODE (0x0c << 20) /* needed for SUB64 codegen comments */#define ARM_RSB_OPCODE CVMARM_RSB_OPCODE#define ARM_RSC_OPCODE (0x0e << 20)#define ARM_UMULL_OPCODE 0x00800090 /* reg32hi,reg32lo = reg32 * reg32.*//* Flow control opcodes: */#define ARM_B_OPCODE (5 << 25) /* branch. */#define ARM_BL_OPCODE (ARM_B_OPCODE | (1 << 24)) /* b and link.*/#ifdef CVM_MP_SAFE#define ARM_LDREX_OPCODE (0x01900f9f)#define ARM_STREX_OPCODE (0x01800f90)#define ARM_MCR_OPCODE (0x0e000000)#define C7 7#define C10 10#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -