📄 jitgrammarrules.jcs
字号:
isVolatile); };// Purpose: STATIC64(staticFieldSpec) = value64.root: ASSIGN STATIC64 reg32 reg64 : 20 : : : : { CVMJITprintCodegenComment(("Do putstatic:")); CVMJITaddCodegenComment((con, "putstatic(staticFieldAddr, value{L|D})")); setStaticField(con, CVMRM_INT_REGS(con), CVMCPU_STR64_OPCODE, CVM_FALSE); };// Purpose: STATIC64VOL(staticFieldSpec) = value64.root: ASSIGN STATIC64VOL reg32 reg64 : 90 : SET_AVOID_C_CALL($$); : SET_TARGET2($$, ARG3, ARG1) : : { CVMRMResource* rhs = popResource(con); CVMRMResource* lhs = popResource(con); /* Swap the arguments because the runtime helper function will expect the 64-bit source value to come first followed by the static field address: */ pushResource(con, rhs); pushResource(con, lhs); CVMJITprintCodegenComment(("Do volatile putstatic:")); CVMJITaddCodegenComment((con, "call CVMCCMruntimePutstatic64Volatile")); CVMJITsetSymbolName((con, "CVMCCMruntimePutstatic64Volatile")); CVMJITstatsRecordInc(con, CVMJIT_STATS_CVMCCMruntimePutstatic64Volatile); /* Call the helper function: */ longBinaryHelper2(con, (void*)CVMCCMruntimePutstatic64Volatile, $$, CVM_FALSE); };aluRhs: ICONST_32 : 0 : : : : { CVMInt32 constant; if (CVMJITirnodeIsConstant32Node($$)) { constant = CVMJITirnodeGetConstant32($$)->j.i; } else { constant = CVMJITirnodeGetConstantAddr($$)->vAddr; } pushALURhsConstant(con, constant); };%{#ifdef CVM_NEED_DO_INT_SHIFT_HELPER/* NOTE: Maybe the shift emitter could be consolidated into the BinaryALU emitter? It seems like the right thing to do. The only reason it is broken out now is because of how the ARM uses it, but it uses override rules now. If it is consolidated in the BINARYALU emitter, then we can, consolidate some codegen rules and helpers. *//* Purpose: Emits code for a shift operation with a const shiftAmount. Also masks off the offset with 0x1f before shifting per VM spec. */static void doIntShift(CVMJITCompilationContext *con, int shiftOp, CVMJITIRNodePtr thisNode, CVMRMregset target, CVMRMregset avoid){ CVMRMResource *lhs = popResource(con); CVMRMResource* dest; int lhsRegNo = CVMRMgetRegisterNumberUnpinned(lhs); CVMInt32 shiftOffset = CVMJITirnodeGetConstant32(CVMJITirnodeGetRightSubtree(thisNode))->j.i; CVMJITRMContext* rc = CVMRM_INT_REGS(con); /* If the dest node has a regHint and the register number is the same as * the register the lhs is already loaded into, then reuse the lhs * register as the dest register. This is common when locals are * shifted. */ if (thisNode->decorationType == CVMJIT_REGHINT_DECORATION && lhsRegNo != -1 && (1U << lhsRegNo) == target && CVMRMgetRefCount(CVMRM_INT_REGS(con), lhs) == 1) { /* relinquish first so dirty resources are not spilled */ CVMRMrelinquishResource(rc, lhs); lhs = NULL; dest = CVMRMgetResourceSpecific(rc, lhsRegNo, 1); CVMassert(lhsRegNo == CVMRMgetRegisterNumber(dest)); } else { /* avoid dest target when pinning lhs */ CVMRMpinResource(rc, lhs, ~target, target); dest = CVMRMgetResource(rc, target, avoid, 1); lhsRegNo = CVMRMgetRegisterNumber(lhs); } CVMCPUemitShiftByConstant(con, shiftOp, CVMRMgetRegisterNumber(dest), lhsRegNo, shiftOffset & 0x1f); if (lhs != NULL) { CVMRMrelinquishResource(rc, lhs); } CVMRMoccupyAndUnpinResource(rc, dest, thisNode); pushResource(con, dest);}#endif#ifdef CVM_NEED_DO_REG_SHIFT_HELPER/* Purpose: Emits code for a shift operation with an unknown shiftAmount. The emitter is responsible for ensuring that the shiftAmount is masked with 0x1f before shifting per VM spec. */static void doRegShift(CVMJITCompilationContext *con, int shiftOp, CVMJITIRNodePtr thisNode, CVMRMregset target, CVMRMregset avoid){ CVMRMResource *rhs = popResource(con); CVMRMResource *lhs = popResource(con); CVMRMResource *dest = CVMRMgetResource(CVMRM_INT_REGS(con), target, avoid, 1); CVMRMpinResource(CVMRM_INT_REGS(con), lhs, CVMRM_ANY_SET, CVMRM_EMPTY_SET); CVMRMpinResource(CVMRM_INT_REGS(con), rhs, CVMRM_ANY_SET, CVMRM_EMPTY_SET); CVMCPUemitShiftByRegister(con, shiftOp, CVMRMgetRegisterNumber(dest), CVMRMgetRegisterNumber(lhs), CVMRMgetRegisterNumber(rhs)); CVMRMrelinquishResource(CVMRM_INT_REGS(con), lhs); CVMRMrelinquishResource(CVMRM_INT_REGS(con), rhs); CVMRMoccupyAndUnpinResource(CVMRM_INT_REGS(con), dest, thisNode); pushResource(con, dest);}#endif%}// Purpose: value32 = value32 << (const32 & 0x1f).reg32: SLL32 reg32 ICONST_32 : 20 : : : CVM_NEED_DO_INT_SHIFT_HELPER : doIntShift(con, CVMCPU_SLL_OPCODE, $$, GET_REGISTER_GOALS);// Purpose: value32 = value32 << (value32 & 0x1f).reg32: SLL32 reg32 reg32 : 20 : : : CVM_NEED_DO_REG_SHIFT_HELPER : doRegShift(con, CVMCPU_SLL_OPCODE, $$, GET_REGISTER_GOALS);// Purpose: value32 = value32 >>> (const32 & 0x1f).reg32: SRL32 reg32 ICONST_32 : 20 : : : CVM_NEED_DO_INT_SHIFT_HELPER : doIntShift(con, CVMCPU_SRL_OPCODE, $$, GET_REGISTER_GOALS);// Purpose: value32 = value32 >>> (value32 & 0x1f).reg32: SRL32 reg32 reg32 : 20 : : : CVM_NEED_DO_REG_SHIFT_HELPER : doRegShift(con, CVMCPU_SRL_OPCODE, $$, GET_REGISTER_GOALS);// Purpose: value32 = value32 >> (const32 & 0x1f).reg32: SRA32 reg32 ICONST_32 : 20 : : : CVM_NEED_DO_INT_SHIFT_HELPER : doIntShift(con, CVMCPU_SRA_OPCODE, $$, GET_REGISTER_GOALS);// Purpose: value32 = value32 >> (value32 & 0x1f).reg32: SRA32 reg32 reg32 : 20 : : : CVM_NEED_DO_REG_SHIFT_HELPER : doRegShift(con, CVMCPU_SRA_OPCODE, $$, GET_REGISTER_GOALS);// Purpose: Converts a value32 into an aluRhs.aluRhs: reg32 : 0 : : : : { /* * a simple matter of bookkeeping. * may be able to (may need to!) delete this rule. * it probably leads to ambiguity. */ CVMRMResource* operand = popResource(con); pushALURhsResource(con, operand); };memSpec: ICONST_32 : 0 : : : : { pushMemSpecImmediate(con, CVMJITirnodeGetConstant32($$)->j.i); };// Purpose: Converts a value32 into a memSpec.memSpec: reg32 : 0 : : : : { /* If a numeric constant is too large, it will be converted into an ICONST_32 which can be mapped into a reg32. This rule will provide a means to use that reg32 as an offset. */ CVMRMResource *operand = popResource(con); pushMemSpecRegister(con, CVM_TRUE, operand); };%{static voidwordUnaryOp( CVMJITCompilationContext* con, int opcode, CVMJITIRNodePtr thisNode, CVMRMregset target, CVMRMregset avoid){ CVMRMResource* src = popResource(con); CVMRMResource* dest = CVMRMgetResource(CVMRM_INT_REGS(con), target, avoid, 1); CVMRMpinResource(CVMRM_INT_REGS(con), src, CVMRM_ANY_SET, CVMRM_EMPTY_SET); CVMCPUemitUnaryALU(con, opcode, CVMRMgetRegisterNumber(dest), CVMRMgetRegisterNumber(src), CVMJIT_NOSETCC); CVMRMrelinquishResource(CVMRM_INT_REGS(con), src); CVMRMoccupyAndUnpinResource(CVMRM_INT_REGS(con), dest, thisNode); pushResource(con, dest);}static voidwordBinaryOp( CVMJITCompilationContext* con, int opcode, CVMJITIRNodePtr thisNode, CVMRMregset target, CVMRMregset avoid){ CVMCPUALURhs* rhs = popALURhs(con); CVMRMResource* lhs = popResource(con); CVMRMResource* dest; int lhsRegNo = CVMRMgetRegisterNumberUnpinned(lhs); CVMJITRMContext* rc = CVMRM_INT_REGS(con);#ifdef IAI_IMPROVED_CONSTANT_ENCODING /* * If rhs is a constant that is not encodable, but the negative of the * constant is, then reverse the sign if doing an Add or Sub. */ if (CVMCPUalurhsIsConstant(rhs) && (opcode == CVMCPU_ADD_OPCODE || opcode == CVMCPU_SUB_OPCODE)) { int op1; int op2; if (opcode == CVMCPU_ADD_OPCODE) { op1 = CVMCPU_ADD_OPCODE; op2 = CVMCPU_SUB_OPCODE; } else { op1 = CVMCPU_SUB_OPCODE; op2 = CVMCPU_ADD_OPCODE; } if (!CVMCPUalurhsIsEncodableAsImmediate(op1, rhs->constValue) && CVMCPUalurhsIsEncodableAsImmediate(op2, -rhs->constValue)) { opcode = op2; rhs->constValue = -rhs->constValue; } }#endif /* avoid dest target when pinning rhs */ CVMCPUalurhsPinResource(rc, opcode, rhs, ~target, target); /* If the dest node has a regHint and the register number is the same as * the register the lhs is already loaded into, then reuse the lhs * register as the dest register. This is common when locals are * incremented. */ if (thisNode->decorationType == CVMJIT_REGHINT_DECORATION && lhsRegNo != -1 && (1U << lhsRegNo) == target && CVMRMgetRefCount(rc, lhs) == 1) { /* relinquish first so dirty resources are not spilled */ CVMRMrelinquishResource(rc, lhs); lhs = NULL; dest = CVMRMgetResourceSpecific(rc, lhsRegNo, 1); CVMassert(lhsRegNo == CVMRMgetRegisterNumber(dest)); } else { /* avoid dest target when pinning lhs */ CVMRMpinResource(rc, lhs, ~target, target); dest = CVMRMgetResource(rc, target, avoid, 1); lhsRegNo = CVMRMgetRegisterNumber(lhs); } CVMCPUemitBinaryALU(con, opcode, CVMRMgetRegisterNumber(dest), lhsRegNo, CVMCPUalurhsGetToken(con, rhs), CVMJIT_NOSETCC); if (lhs != NULL) { CVMRMrelinquishResource(rc, lhs); } CVMCPUalurhsRelinquishResource(rc, rhs); CVMRMoccupyAndUnpinResource(rc, dest, thisNode); pushResource(con, dest);}#ifdef CVM_NEED_WORD_BINARY_OP_WITH_REG32_RHSstatic voidwordBinaryOpWithReg32Rhs( CVMJITCompilationContext* con, int opcode, CVMJITIRNodePtr thisNode, CVMRMregset target, CVMRMregset avoid){ CVMRMResource* operand = popResource(con); pushALURhsResource(con, operand); wordBinaryOp(con, opcode, thisNode, target, avoid);}#endif/* Purpose: Emits a call to a Unary CCM helper. */static voidunaryHelper( CVMJITCompilationContext *con, void *helperAddress, CVMJITIRNodePtr thisNode, CVMRMregset outgoingSpillRegSet, int resultSize){ CVMRMResource *src = popResource(con); CVMRMResource *dest; /* Pin the input to CVMCPU_ARG1_REG because the helper expects it there: */ src = CVMRMpinResourceSpecific(CVMRM_INT_REGS(con), src, CVMCPU_ARG1_REG); /* Spill the outgoing registers if necessary: */ CVMRMminorSpill(con, outgoingSpillRegSet);#ifdef CVMCPU_HAS_64BIT_REGISTERS { int argSize = CVMRMgetSize(src); if (argSize == 2) { /* argSize = 2 means the argument is doubleword */ CVMCPUemitMoveTo64BitRegister(con, CVMCPU_ARG1_REG, CVMCPU_ARG1_REG); } }#endif /* Emit the call to the helper to compute the result: */ CVMCPUemitAbsoluteCall(con, helperAddress, CVMJIT_CPDUMPOK, CVMJIT_CPBRANCHOK); CVMJITcsBeginBlock(con);#ifdef CVMCPU_HAS_64BIT_REGISTERS { if (resultSize == 2) { /* resultSize = 2 means the result is doubleword. */ CVMCPUemitMoveFrom64BitRegister(con, CVMCPU_RESULT1_REG, CVMCPU_RESULT1_REG); } }#endif /* Release resources and publish the result: */ CVMRMrelinquishResource(CVMRM_INT_REGS(con), src); dest = CVMRMgetResourceSpecific(CVMRM_INT_REGS(con), CVMCPU_RESULT1_REG, resultSize); CVMRMoccupyAndUnpinResource(CVMRM_INT_REGS(con), dest, thisNode); pushResource(con, dest);}/* Purpose: Emits a call to a Binary CCM helper. */static voidbinaryHelper( CVMJITCompilationContext *con, void* helperAddress, CVMJITIRNodePtr thisNode, CVMBool checkZero, int argSize, /* total size in words of all arguments */ int resultSize){ const char *symbolName; CVMCodegenComment *comment; CVMRMResource* rhs = popResource(con); CVMRMResource* lhs = popResource(con); CVMRMResource* dest; int lhsReg, rhsReg; CVMRMregset outSet; CVMJITpopSymbolName(con, symbolName); CVMJITpopCodegenComment(con, comment); lhsReg = CVMCPU_ARG1_REG; if (argSize == 2) { rhsReg = CVMCPU_ARG2_REG; outSet = ARG1|ARG2; } else if (argSize == 3){ rhsReg = CVMCPU_ARG3_REG; outSet = ARG1|ARG2|ARG3; } else { CVMassert(argSize == 4); rhsReg = CVMCPU_ARG3_REG; outSet = ARG1|ARG2|ARG3|ARG4; } /* Pin the input to the first two arguments because the helper expects it there. Note that if the rhs is already in a register, then pin it first so it is setup using a move instruction. Otherwise you run the risk of it getting clobbered when pinning the lhs, and then having to reload if from memory (after possibly also having spilled it). */ if (CVMRMgetRegisterNumberUnpinned(rhs) != -1) { rhs = CVMRMpinResourceSpecific(CVMRM_INT_REGS(con), rhs, rhsReg); lhs = CVMRMpinResourceSpecific(CVMRM_INT_REGS(con), lhs, lhsReg); } else { rhs = CVMRMpinResourceSpecific(CVMRM_INT_REGS(con), rhs, rhsReg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -