📄 jitemitter_cpu.c
字号:
(CVMUint32)opcode | lhsRegID << 16 | rhsToken); CVMtraceJITCodegenExec({ char mode1buf[48]; formatMode1(mode1buf, rhsToken); printPC(con); CVMconsolePrintf(" %s%s %s, %s", getOpcodeName(opcode), conditions[condCode], regNames[lhsRegID], mode1buf); }); CVMJITdumpCodegenComments(con);}extern voidCVMCPUemitCompare(CVMJITCompilationContext* con, int opcode, CVMCPUCondCode condCode, int lhsRegID, CVMCPUALURhsToken rhsToken){ CVMARMemitCompareConditional(con, opcode, lhsRegID, rhsToken, CVMCPU_COND_AL);}extern voidCVMCPUemitCompareConstant(CVMJITCompilationContext* con, int opcode, CVMCPUCondCode condCode, int lhsRegID, CVMInt32 rhsConstValue){ CVMCPUALURhsToken rhsToken; CVMRMResource* rhsRes; /* rhsConstValue may not be encodable as an immediate value */ if (CVMCPUalurhsIsEncodableAsImmediate(opcode, rhsConstValue)) { rhsRes = NULL; rhsToken = CVMARMalurhsEncodeConstantToken(con, rhsConstValue); } else { rhsRes = CVMRMgetResourceForConstant32(CVMRM_INT_REGS(con), CVMRM_ANY_SET, CVMRM_EMPTY_SET, rhsConstValue); rhsToken = CVMARMalurhsEncodeRegisterToken(con, CVMRMgetRegisterNumber(rhsRes)); } CVMARMemitCompareConditional(con, opcode, lhsRegID, rhsToken, CVMCPU_COND_AL); if (rhsRes != NULL) { CVMRMrelinquishResource(CVMRM_INT_REGS(con), rhsRes); }}/* * Putting a big, non-immediate value into a register * using the constant pool. */voidCVMCPUemitLoadConstant( CVMJITCompilationContext* con, int regno, CVMInt32 v){ CVMCPUemitLoadConstantConditional(con, regno, v, CVMCPU_COND_AL);}voidCVMCPUemitLoadConstantConditional( CVMJITCompilationContext* con, int regno, CVMInt32 v, CVMCPUCondCode condCode){ CVMUint32 base; CVMUint32 rotate;#ifdef CVM_JIT_USE_FP_HARDWARE CVMRMResource *res = CVMRMfindResourceConstant32InRegister(CVMRM_FP_REGS(con), v); if (res != NULL) { CVMARMemitMoveFloatFP(con, CVMARM_MOVAF_OPCODE, CVMRMgetRegisterNumberUnpinned(res), regno); } else#endif /* Check to see if we can do this as a positive constant: */ if (CVMARMmode1EncodeImmediate(v, &base, &rotate)) { CVMCPUemitMoveConditional(con, CVMCPU_MOV_OPCODE, regno, CVMARMalurhsEncodeLargeConstantToken(base, rotate), CVMJIT_NOSETCC, condCode); /* Check to see if we can do this as a negative constant: */ } else if (CVMARMmode1EncodeImmediate(~v, &base, &rotate)) { CVMCPUemitMoveConditional(con, ARM_MVN_OPCODE, regno, CVMARMalurhsEncodeLargeConstantToken(base, rotate), CVMJIT_NOSETCC, condCode); /* Do a big constant stored at a PC relative location: */ } else { CVMInt32 logicalPC = CVMJITcbufGetLogicalPC(con); CVMInt32 targetLiteralOffset = 0; CVMInt32 relativeOffset = 0; int baseReg; /* * Normally we call CVMJITgetRuntimeConstantReference32 first and * then emit the instruction to load the constant afterwards. * When code scheduling is enabled, the instruction to load the * constant might be emitted somewhere other than the current * logicalPC, so when code scheduling is enabled we need to wait * until after the load instruction is emitted before calling * CVMJITgetRuntimeConstantReference32. */#ifndef IAI_CODE_SCHEDULER_SCORE_BOARD targetLiteralOffset = CVMJITgetRuntimeConstantReference32(con, logicalPC, v);#endif /* IAI_CODE_SCHEDULER_SCORE_BOARD */#ifdef CVMCPU_HAS_CP_REG baseReg = CVMCPU_CP_REG; /* offset of 0 will be patched after the constant pool is dumped */ relativeOffset = 0;#else baseReg = CVMARM_PC; logicalPC += 8; /* +8 ARM PC bias */ relativeOffset = (targetLiteralOffset != 0) ? targetLiteralOffset - logicalPC : 0;#endif /* Emit the load relative to the constant pool base register. */ CVMCPUemitMemoryReferenceConditional(con, CVMCPU_LDR32_OPCODE, regno, baseReg, CVMCPUmemspecEncodeImmediateToken(con, relativeOffset), condCode);#ifdef IAI_CODE_SCHEDULER_SCORE_BOARD /* * Find out where the load instruction was emitted and pass this to * CVMJITgetRuntimeConstantReference32. If the constant was * already emitted, then we need to patch up the load * instruction now. */ logicalPC = CVMJITcbufGetLogicalInstructionPC(con); targetLiteralOffset = CVMJITgetRuntimeConstantReference32(con, logicalPC, v); targetLiteralOffset = (targetLiteralOffset != 0) ? targetLiteralOffset : logicalPC; /* Emit the load relative to the constant pool base register. */ CVMJITfixupAddress(con, logicalPC, targetLiteralOffset, CVMJIT_MEMSPEC_ADDRESS_MODE);#endif /* IAI_CODE_SCHEDULER_SCORE_BOARD */ } CVMJITresetSymbolName(con);}static int absolute(int v){ return (v<0)?-v:v;}#ifdef CVM_JIT_USE_FP_HARDWARE/* This function can dump constant pool and so to update logical address in the context */static CVMInt32CVMARMgetRuntimeConstantReferenceFP( CVMJITCompilationContext* con, CVMInt32 v){ if (con->constantPoolSize >= CVMARM_FP_MAX_LOADSTORE_OFFSET) { CVMRISCemitConstantPoolDumpWithBranchAround(con); } return CVMJITgetRuntimeFPConstantReference32(con, CVMJITcbufGetLogicalPC(con), v);}voidCVMCPUemitLoadConstantConditionalFP( CVMJITCompilationContext* con, int regno, CVMInt32 v, CVMCPUCondCode condCode){ CVMInt32 targetLiteralOffset; CVMInt32 logicalPC; int baseReg; CVMInt32 relativeOffset; CVMRMResource *res = CVMRMfindResourceConstant32InRegister(CVMRM_FP_REGS(con), v); if (res != NULL) { if (regno != CVMRMgetRegisterNumberUnpinned(res)) { CVMCPUemitMoveConditional(con, CVMCPU_FMOV_OPCODE, regno, CVMRMgetRegisterNumberUnpinned(res), CVMJIT_NOSETCC, condCode); } CVMJITresetSymbolName(con); return; } res = CVMRMfindResourceConstant32InRegister(CVMRM_INT_REGS(con), v); if (res != NULL) { CVMARMemitMoveFloatFP(con, CVMARM_MOVFA_OPCODE, regno, CVMRMgetRegisterNumberUnpinned(res)); CVMJITresetSymbolName(con); return; } if (v == 0) { res = CVMRMfindResourceForNonNaNConstant(CVMRM_FP_REGS(con)); if (res != NULL) { CVMCPUemitBinaryFP(con, CVMCPU_FSUB_OPCODE, regno, CVMRMgetRegisterNumberUnpinned(res), CVMRMgetRegisterNumberUnpinned(res)); CVMJITresetSymbolName(con); return; } res = CVMRMfindResourceForNonNaNConstant(CVMRM_INT_REGS(con)); if (res != NULL) { CVMARMemitMoveFloatFP(con, CVMARM_MOVFA_OPCODE, regno, CVMRMgetRegisterNumberUnpinned(res)); CVMCPUemitBinaryFP(con, CVMCPU_FSUB_OPCODE, regno, regno, regno); CVMJITresetSymbolName(con); return; } { /* Load 0 into ARM register */ CVMRMResource *tempReg = CVMRMgetResource(CVMRM_INT_REGS(con), CVMRM_ANY_SET, CVMRM_EMPTY_SET, 1); CVMInt32 tempRegID = CVMRMgetRegisterNumber(tempReg); CVMCPUemitLoadConstant(con, tempRegID, 0); CVMARMemitMoveFloatFP(con, CVMARM_MOVFA_OPCODE, regno, tempRegID); CVMRMrelinquishResource(CVMRM_INT_REGS(con), tempReg); CVMJITresetSymbolName(con); return; } } targetLiteralOffset = CVMARMgetRuntimeConstantReferenceFP(con, v); logicalPC = CVMJITcbufGetLogicalPC(con);#ifdef CVMCPU_HAS_CP_REG baseReg = CVMCPU_CP_REG; /* offset of 0 will be patched after the constant pool is dumped */ relativeOffset = 0;#else baseReg = CVMARM_PC; relativeOffset = (targetLiteralOffset != 0) ? targetLiteralOffset - logicalPC - 8 : 0;#endif /* Emit the load relative to the constant pool base register. */ CVMCPUemitMemoryReferenceConditional(con, CVMCPU_FLDR32_OPCODE, regno, baseReg, CVMCPUmemspecEncodeImmediateToken(con, relativeOffset), condCode); CVMJITresetSymbolName(con);}#endif/* * This is for emitting the sequence necessary for doing a call to an * absolute target. The target can either be in the code cache * or to a vm function. For the former, it will choose the quicker bl * instruction. For the later, it will use the 2 instruction <mov, ldr> * pair to setup the lr and load the target address into the pc, plus * generate a constant for the target address. * * condCode is the condition that must be met to do the call. * * The constant pool will be dumped if necessary and if allowed. * If okToBranchAroundCpDump is FALSE and the lr can't be setup * use mode1 math to skip over the constant pool, then it will not * be dumped. * * WARNING: pass FALSE for okToBranchAroundCpDump if you are going * to capture a stackmap right after calling CVMCPUemitAbsoluteCall(). * Otherwise the pc flushed to the frame will not be the pc where the * stackmap was captured. */static voidemitReturnAddressComputation(CVMJITCompilationContext* con, CVMCPUCondCode condCode, int skip){ CVMassert(skip >= 0); CVMJITcsSetEmitInPlace(con); CVMJITcsSetDestRegister(con, CVMARM_LR); CVMJITcsPushSourceRegister(con, CVMARM_PC); if (skip == 0) { emitInstruction(con, ARM_MAKE_CONDCODE_BITS(condCode) | (CVMUint32)CVMCPU_MOV_OPCODE | CVMARM_LR << 12 | CVMARM_PC); } else { CVMUint32 base, rotate; CVMBool success; CVMassert(skip > 0); /* Make sure skip is reachable via mode1 addressing: */ success = CVMARMmode1EncodeImmediate(skip, &base, &rotate); CVMassert(success); emitInstruction(con, ARM_MAKE_CONDCODE_BITS(condCode) | (CVMUint32)CVMCPU_ADD_OPCODE | CVMARM_PC << 16 | CVMARM_LR << 12 | CVMARM_MODE1_CONSTANT | rotate << 8 | base); } CVMtraceJITCodegenExec({ printPC(con); if (skip == 0){ CVMJITaddCodegenComment((con, "lr = pc")); CVMconsolePrintf(" mov%s %s, %s", conditions[condCode], regNames[CVMARM_LR], regNames[CVMARM_PC]); } else { CVMJITaddCodegenComment((con, "lr = pc + offset")); CVMconsolePrintf(" add%s %s, %s, %d", conditions[condCode], regNames[CVMARM_LR], regNames[CVMARM_PC], skip); } }); CVMJITcsClearEmitInPlace(con); CVMJITdumpCodegenComments(con);}voidCVMCPUemitFlushJavaStackFrameAndAbsoluteCall(CVMJITCompilationContext* con, const void* target, CVMBool okToDumpCp, CVMBool okToBranchAroundCpDump){ CVMCodegenComment *comment; CVMJITpopCodegenComment(con, comment); /* Store the JSP into the compiled frame: */ CVMCPUemitMemoryReferenceImmediate(con, CVMCPU_STR32_OPCODE, CVMCPU_JSP_REG, CVMCPU_JFP_REG, offsetof(CVMFrame, topOfStack)); CVMJITpushCodegenComment(con, comment); CVMARMemitAbsoluteCallConditional(con, target, okToDumpCp, okToBranchAroundCpDump, CVMCPU_COND_AL, CVM_TRUE); CVMJITcsBeginBlock(con);}voidCVMARMemitAbsoluteCallConditional(CVMJITCompilationContext* con, const void* target, CVMBool okToDumpCp, CVMBool okToBranchAroundCpDump, CVMCPUCondCode condCode, CVMBool flushReturnPCToFrame){ CVMCodegenComment *comment; CVMBool doCpDump = okToDumpCp && CVMJITcpoolNeedDump(con); int cpSkip = 0; CVMBool cpSkipIsMode1 = CVM_FALSE; int minSkip = 0; if (flushReturnPCToFrame) { minSkip = 4; } /* * Find out if we can use a mode1 instruction to adjust the lr to * skip over the constant pool. */ if (doCpDump) { cpSkip = (con->numEntriesToEmit * 4) + minSkip; if (condCode != CVMCPU_COND_AL) { cpSkip += 4; /* need to skip around absolute branch */ } cpSkipIsMode1 = CVMARMmode1EncodeImmediate(cpSkip, NULL, NULL); /* * If the call is conditional or the skip value is not mode1, then * we will have to branch around the the constant pool. If the * branch is not allowed, then we can't dump. */ if (condCode != CVMCPU_COND_AL || !cpSkipIsMode1) { doCpDump = okToBranchAroundCpDump; if (!doCpDump) { cpSkip = minSkip; } } } else { cpSkip = minSkip; } /* The emitted code should look like one of the following cases: CASE 1: No constants to dump. add lr, pc, #4 str lr, [JFP, #offsetof(CVMCompiledFrame, pcX)] ldr pc, #target @ target not in code cache return_ad
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -