TR::Instruction * TR_X86SystemLinkage::savePreservedRegisters(TR::Instruction *cursor) { // For IA32, if disableShrinkWrapping, usePushForPreservedRegs will be true; otherwise false; // For X64, shrinkWraping is always on, and usePushForPreservedRegs always false; // TR_ASSERT(!getProperties().getUsesPushesForPreservedRegs(), "assertion failure"); TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol(); const int32_t localSize = getProperties().getOffsetToFirstLocal() - bodySymbol->getLocalMappingCursor(); const int32_t pointerSize = getProperties().getPointerSize(); int32_t offsetCursor = -localSize + getProperties().getOffsetToFirstLocal() - pointerSize; if (_properties.getUsesPushesForPreservedRegs()) { for (int32_t pindex = _properties.getMaxRegistersPreservedInPrologue()-1; pindex >= 0; pindex--) { TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex); TR::RealRegister *reg = machine()->getX86RealRegister(idx); if (reg->getHasBeenAssignedInMethod() && reg->getState() != TR::RealRegister::Locked) { cursor = new (trHeapMemory()) TR::X86RegInstruction(cursor, PUSHReg, reg, cg()); } } } else { TR_BitVector *p = cg()->getPreservedRegsInPrologue(); for (int32_t pindex = getProperties().getMaxRegistersPreservedInPrologue()-1; pindex >= 0; pindex--) { TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex); TR::RealRegister *reg = machine()->getX86RealRegister(getProperties().getPreservedRegister((uint32_t)pindex)); if(reg->getHasBeenAssignedInMethod() && reg->getState() != TR::RealRegister::Locked) { if (!p || p->get(idx)) { cursor = generateMemRegInstruction( cursor, movOpcodes[MemReg][fullRegisterMovType(reg)], generateX86MemoryReference(machine()->getX86RealRegister(TR::RealRegister::vfp), offsetCursor, cg()), reg, cg() ); } offsetCursor -= pointerSize; } } } return cursor; }
TR::Instruction * TR::X86SystemLinkage::savePreservedRegisters(TR::Instruction *cursor) { // For IA32 usePushForPreservedRegs will be true; // For X64, usePushForPreservedRegs always false; TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol(); const int32_t localSize = getProperties().getOffsetToFirstLocal() - bodySymbol->getLocalMappingCursor(); const int32_t pointerSize = getProperties().getPointerSize(); int32_t offsetCursor = -localSize + getProperties().getOffsetToFirstLocal() - pointerSize; if (_properties.getUsesPushesForPreservedRegs()) { for (int32_t pindex = _properties.getMaxRegistersPreservedInPrologue()-1; pindex >= 0; pindex--) { TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex); TR::RealRegister *reg = machine()->getX86RealRegister(idx); if (reg->getHasBeenAssignedInMethod() && reg->getState() != TR::RealRegister::Locked) { cursor = new (trHeapMemory()) TR::X86RegInstruction(cursor, PUSHReg, reg, cg()); } } } else { for (int32_t pindex = getProperties().getMaxRegistersPreservedInPrologue()-1; pindex >= 0; pindex--) { TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex); TR::RealRegister *reg = machine()->getX86RealRegister(getProperties().getPreservedRegister((uint32_t)pindex)); if(reg->getHasBeenAssignedInMethod() && reg->getState() != TR::RealRegister::Locked) { cursor = generateMemRegInstruction( cursor, TR::Linkage::movOpcodes(MemReg, fullRegisterMovType(reg)), generateX86MemoryReference(machine()->getX86RealRegister(TR::RealRegister::vfp), offsetCursor, cg()), reg, cg() ); offsetCursor -= pointerSize; } } } return cursor; }
// Build arguments for system linkage dispatch. // int32_t TR::AMD64SystemLinkage::buildArgs( TR::Node *callNode, TR::RegisterDependencyConditions *deps) { TR::SymbolReference *methodSymRef = callNode->getSymbolReference(); TR::MethodSymbol *methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol(); TR::RealRegister::RegNum noReg = TR::RealRegister::NoReg; TR::RealRegister *espReal = machine()->getX86RealRegister(TR::RealRegister::esp); int32_t firstNodeArgument = callNode->getFirstArgumentIndex(); int32_t lastNodeArgument = callNode->getNumChildren() - 1; int32_t offset = 0; int32_t sizeOfOutGoingArgs= 0; uint16_t numIntArgs = 0, numFloatArgs = 0; int32_t first, last, direction; int32_t numCopiedRegs = 0; TR::Register *copiedRegs[TR::X86LinkageProperties::MaxArgumentRegisters]; if (getProperties().passArgsRightToLeft()) { first = lastNodeArgument; last = firstNodeArgument - 1; direction = -1; } else { first = firstNodeArgument; last = lastNodeArgument + 1; direction = 1; } // If the dispatch is indirect we must add the VFT register to the preconditions // so that it gets register assigned with the other preconditions to the call. // if (callNode->getOpCode().isIndirect()) { TR::Node *vftChild = callNode->getFirstChild(); TR_ASSERT(vftChild->getRegister(), "expecting VFT child to be evaluated"); TR::RealRegister::RegNum scratchRegIndex = getProperties().getIntegerScratchRegister(1); deps->addPreCondition(vftChild->getRegister(), scratchRegIndex, cg()); } int32_t i; for (i = first; i != last; i += direction) { TR::parmLayoutResult layoutResult; TR::RealRegister::RegNum rregIndex = noReg; TR::Node *child = callNode->getChild(i); layoutParm(child, sizeOfOutGoingArgs, numIntArgs, numFloatArgs, layoutResult); if (layoutResult.abstract & TR::parmLayoutResult::IN_LINKAGE_REG_PAIR) { // TODO: AMD64 SysV ABI might put a struct into a pair of linkage registerr TR_ASSERT(false, "haven't support linkage_reg_pair yet.\n"); } else if (layoutResult.abstract & TR::parmLayoutResult::IN_LINKAGE_REG) { TR_RegisterKinds regKind = layoutResult.regs[0].regKind; uint32_t regIndex = layoutResult.regs[0].regIndex; TR_ASSERT(regKind == TR_GPR || regKind == TR_FPR, "linkage registers includes TR_GPR and TR_FPR\n"); rregIndex = (regKind == TR_FPR) ? getProperties().getFloatArgumentRegister(regIndex): getProperties().getIntegerArgumentRegister(regIndex); } else { offset = layoutResult.offset; } TR::Register *vreg; vreg = cg()->evaluate(child); bool needsStackOffsetUpdate = false; if (rregIndex != noReg) { // For NULL JNI reference parameters, it is possible that the NULL value will be evaluated into // a different register than the child. In that case it is not necessary to copy the temporary scratch // register across the call. // if ((child->getReferenceCount() > 1) && (vreg == child->getRegister())) { TR::Register *argReg = cg()->allocateRegister(); if (vreg->containsCollectedReference()) argReg->setContainsCollectedReference(); generateRegRegInstruction(TR::Linkage::movOpcodes(RegReg, movType(child->getDataType())), child, argReg, vreg, cg()); vreg = argReg; copiedRegs[numCopiedRegs++] = vreg; } deps->addPreCondition(vreg, rregIndex, cg()); } else { // Ideally, we would like to push rather than move generateMemRegInstruction(TR::Linkage::movOpcodes(MemReg, fullRegisterMovType(vreg)), child, generateX86MemoryReference(espReal, offset, cg()), vreg, cg()); } cg()->decReferenceCount(child); } // Now that we're finished making the preconditions, all the interferences // are established and we can kill these regs. // for (i = 0; i < numCopiedRegs; i++) cg()->stopUsingRegister(copiedRegs[i]); deps->stopAddingPreConditions(); return sizeOfOutGoingArgs; }