void TR_Debug::print(TR::FILE *pOutFile, TR::AMD64FPConversionSnippet * snippet) { if (pOutFile == NULL) return; uint8_t *bufferPos = snippet->getSnippetLabel()->getCodeLocation(); printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, getName(snippet)); TR::Machine *machine = _cg->machine(); TR::RealRegister *sourceRegister = toRealRegister(snippet->getConvertInstruction()->getSourceRegister()); TR::RealRegister *targetRegister = toRealRegister(snippet->getConvertInstruction()->getTargetRegister()); uint8_t sreg = sourceRegister->getRegisterNumber(); uint8_t treg = targetRegister->getRegisterNumber(); TR::ILOpCodes opCode = snippet->getConvertInstruction()->getNode()->getOpCodeValue(); TR_RegisterSizes size = TR_DoubleWordReg; if (treg != TR::RealRegister::eax) { int instrSize = IS_REX(*bufferPos)? 3 : 2; printPrefix(pOutFile, NULL, bufferPos, instrSize); trfprintf(pOutFile, "mov \t"); print(pOutFile, targetRegister, size); trfprintf(pOutFile, ", "); print(pOutFile, machine->getX86RealRegister(TR::RealRegister::eax), size); trfprintf(pOutFile, "\t%s preserve helper return reg", commentString()); bufferPos += instrSize; } if (sreg != TR::RealRegister::xmm0) { printPrefix(pOutFile, NULL, bufferPos, 4); trfprintf(pOutFile, "sub \trsp, 8"); printPrefix(pOutFile, NULL, bufferPos, 5); trfprintf(pOutFile, "movsd\t[rsp], xmm0\t%s save xmm0", commentString()); bufferPos += 9; int instrSize = IS_REX(*bufferPos)? 5 : 4; printPrefix(pOutFile, NULL, bufferPos, instrSize); trfprintf(pOutFile, "movsd\txmm0, "); print(pOutFile, sourceRegister, TR_QuadWordReg); trfprintf(pOutFile, "\t%s load parameter", commentString()); bufferPos += instrSize; } printPrefix(pOutFile, NULL, bufferPos, 5); trfprintf(pOutFile, "call\t%s", getName(snippet->getHelperSymRef())); bufferPos += 5; if (sreg != TR::RealRegister::xmm0) { printPrefix(pOutFile, NULL, bufferPos, 5); trfprintf(pOutFile, "movsd\txmm0, [rsp]\t%s restore xmm0", commentString()); printPrefix(pOutFile, NULL, bufferPos, 4); trfprintf(pOutFile, "add \trsp, 8"); bufferPos += 9; } if (treg != TR::RealRegister::eax) { int instrSize = IS_REX(*bufferPos)? 2 : 1; printPrefix(pOutFile, NULL, bufferPos, instrSize); trfprintf(pOutFile, "xchg\t"); print(pOutFile, targetRegister, size); trfprintf(pOutFile, ", "); print(pOutFile, machine->getX86RealRegister(TR::RealRegister::eax), size); trfprintf(pOutFile, "\t%s restore result reg & put result in target reg", commentString()); bufferPos += instrSize; } printRestartJump(pOutFile, snippet, bufferPos); }
// Copies parameters from where they enter the method (either on stack or in a // linkage register) to their "home location" where the method body will expect // to find them (either on stack or in a global register). // TR::Instruction * TR::X86SystemLinkage::copyParametersToHomeLocation(TR::Instruction *cursor) { TR::Machine *machine = cg()->machine(); TR::RealRegister *framePointer = machine->getX86RealRegister(TR::RealRegister::vfp); TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol(); ListIterator<TR::ParameterSymbol> paramIterator(&(bodySymbol->getParameterList())); TR::ParameterSymbol *paramCursor; const TR::RealRegister::RegNum noReg = TR::RealRegister::NoReg; TR_ASSERT(noReg == 0, "noReg must be zero so zero-initializing movStatus will work"); TR::MovStatus movStatus[TR::RealRegister::NumRegisters] = {{(TR::RealRegister::RegNum)0,(TR::RealRegister::RegNum)0,(TR_MovDataTypes)0}}; // We must always do the stores first, then the reg-reg copies, then the // loads, so that we never clobber a register we will need later. However, // the logic is simpler if we do the loads and stores in the same loop. // Therefore, we maintain a separate instruction cursor for the loads. // // We defer the initialization of loadCursor until we generate the first // load. Otherwise, if we happen to generate some stores first, then the // store cursor would get ahead of the loadCursor, and the instructions // would end up in the wrong order despite our efforts. // TR::Instruction *loadCursor = NULL; // Phase 1: generate RegMem and MemReg movs, and collect information about // the required RegReg movs. // for (paramCursor = paramIterator.getFirst(); paramCursor != NULL; paramCursor = paramIterator.getNext()) { int8_t lri = paramCursor->getLinkageRegisterIndex(); // How the parameter enters the method TR::RealRegister::RegNum ai // Where method body expects to find it = (TR::RealRegister::RegNum)paramCursor->getAllocatedIndex(); int32_t offset = paramCursor->getParameterOffset(); // Location of the parameter's stack slot TR_MovDataTypes movDataType = paramMovType(paramCursor); // What sort of MOV instruction does it need? // Copy the parameter to wherever it should be // if (lri == NOT_LINKAGE) // It's on the stack { if (ai == NOT_ASSIGNED) // It only needs to be on the stack { // Nothing to do } else // Method body expects it to be in the ai register { if (loadCursor == NULL) loadCursor = cursor; if (debug("traceCopyParametersToHomeLocation")) diagnostic("copyParametersToHomeLocation: Loading %d\n", ai); // ai := stack loadCursor = generateRegMemInstruction( loadCursor, TR::Linkage::movOpcodes(RegMem, movDataType), machine->getX86RealRegister(ai), generateX86MemoryReference(framePointer, offset, cg()), cg() ); } } else // It's in a linkage register { TR::RealRegister::RegNum sourceIndex = getProperties().getArgumentRegister(lri, isFloat(movDataType)); // Copy to the stack if necessary // if (ai == NOT_ASSIGNED || hasToBeOnStack(paramCursor)) { if (comp()->getOption(TR_TraceCG)) traceMsg(comp(), "copyToHomeLocation param %p, linkage reg index %d, allocated index %d, parameter offset %d, hasToBeOnStack %d, parm->isParmHasToBeOnStack() %d.\n", paramCursor, lri, ai, offset, hasToBeOnStack(paramCursor), paramCursor->isParmHasToBeOnStack()); if (debug("traceCopyParametersToHomeLocation")) diagnostic("copyParametersToHomeLocation: Storing %d\n", sourceIndex); // stack := lri cursor = generateMemRegInstruction( cursor, TR::Linkage::movOpcodes(MemReg, movDataType), generateX86MemoryReference(framePointer, offset, cg()), machine->getX86RealRegister(sourceIndex), cg() ); } // Copy to the ai register if necessary // if (ai != NOT_ASSIGNED && ai != sourceIndex) { // This parameter needs a RegReg move. We don't know yet whether // we need the value in the target register, so for now we just // remember that we need to do this and keep going. // TR_ASSERT(movStatus[ai ].sourceReg == noReg, "Each target reg must have only one source"); TR_ASSERT(movStatus[sourceIndex].targetReg == noReg, "Each source reg must have only one target"); if (debug("traceCopyParametersToHomeLocation")) diagnostic("copyParametersToHomeLocation: Planning to move %d to %d\n", sourceIndex, ai); movStatus[ai].sourceReg = sourceIndex; movStatus[sourceIndex].targetReg = ai; movStatus[sourceIndex].outgoingDataType = movDataType; } if (debug("traceCopyParametersToHomeLocation") && ai == sourceIndex) { diagnostic("copyParametersToHomeLocation: Parameter #%d already in register %d\n", lri, ai); } } } // Phase 2: Iterate through the parameters again to insert the RegReg moves. // for (paramCursor = paramIterator.getFirst(); paramCursor != NULL; paramCursor = paramIterator.getNext()) { if (paramCursor->getLinkageRegisterIndex() == NOT_LINKAGE) continue; const TR::RealRegister::RegNum paramReg = getProperties().getArgumentRegister(paramCursor->getLinkageRegisterIndex(), isFloat(paramMovType(paramCursor))); if (movStatus[paramReg].targetReg == 0) { // This parameter does not need to be copied anywhere if (debug("traceCopyParametersToHomeLocation")) diagnostic("copyParametersToHomeLocation: Not moving %d\n", paramReg); } else { if (debug("traceCopyParametersToHomeLocation")) diagnostic("copyParametersToHomeLocation: Preparing to move %d\n", paramReg); // If a mov's target register is the source for another mov, we need // to do that other mov first. The idea is to find the end point of // the chain of movs starting with paramReg and ending with a // register whose current value is not needed; then do that chain of // movs in reverse order. // TR_ASSERT(noReg == 0, "noReg must be zero (not %d) for zero-filled initialization to work", noReg); TR::RealRegister::RegNum regCursor; // Find the last target in the chain // regCursor = movStatus[paramReg].targetReg; while(movStatus[regCursor].targetReg != noReg) { // Haven't found the end yet regCursor = movStatus[regCursor].targetReg; TR_ASSERT(regCursor != paramReg, "Can't yet handle cyclic dependencies"); // TODO:AMD64 Use scratch register to break cycles // A properly-written pickRegister should never // cause cycles to occur in the first place. However, we may want // to consider adding cycle-breaking logic so that (1) pickRegister // has more flexibility, and (2) we're more robust against // otherwise harmless bugs in pickRegister. } // Work our way backward along the chain, generating all the necessary movs // while(movStatus[regCursor].sourceReg != noReg) { TR::RealRegister::RegNum source = movStatus[regCursor].sourceReg; if (debug("traceCopyParametersToHomeLocation")) diagnostic("copyParametersToHomeLocation: Moving %d to %d\n", source, regCursor); // regCursor := regCursor.sourceReg cursor = generateRegRegInstruction( cursor, TR::Linkage::movOpcodes(RegReg, movStatus[source].outgoingDataType), machine->getX86RealRegister(regCursor), machine->getX86RealRegister(source), cg() ); // Update movStatus as we go so we don't generate redundant movs movStatus[regCursor].sourceReg = noReg; movStatus[source ].targetReg = noReg; // Continue with the next register in the chain regCursor = source; } } } // Return the last instruction we inserted, whether or not it was a load. // return loadCursor? loadCursor : cursor; }
void OMR::X86::Instruction::assignRegisters(TR_RegisterKinds kindsToBeAssigned) { if (!self()->getDependencyConditions()) { // Fast path when there are no dependency conditions. // return; } if (self()->getOpCodeValue() != ASSOCREGS) { self()->aboutToAssignRegDeps(); if ((self()->cg()->getAssignmentDirection() == self()->cg()->Backward)) { self()->getDependencyConditions()->assignPostConditionRegisters(self(), kindsToBeAssigned, self()->cg()); self()->getDependencyConditions()->assignPreConditionRegisters(self(), kindsToBeAssigned, self()->cg()); } else { self()->getDependencyConditions()->assignPreConditionRegisters(self()->getPrev(), kindsToBeAssigned, self()->cg()); self()->getDependencyConditions()->assignPostConditionRegisters(self(), kindsToBeAssigned, self()->cg()); } } else if ((self()->getOpCodeValue() == ASSOCREGS) && self()->cg()->enableRegisterAssociations()) { if (kindsToBeAssigned & TR_GPR_Mask) { TR::Machine *machine = self()->cg()->machine(); // First traverse the existing associations and remove them // so that they don't interfere with the new ones // for (int i = TR::RealRegister::FirstGPR; i <= TR::RealRegister::LastAssignableGPR; ++i) { // Skip non-assignable registers // if (machine->getX86RealRegister((TR::RealRegister::RegNum)i)->getState() == TR::RealRegister::Locked) continue; TR::Register *virtReg = machine->getVirtualAssociatedWithReal((TR::RealRegister::RegNum)i); if (virtReg) { virtReg->setAssociation(TR::RealRegister::NoReg); } } // Next loop through and set up the new associations (both on the machine // and by associating the virtual registers with their real dependencies) // TR_X86RegisterDependencyGroup *depGroup = self()->getDependencyConditions()->getPostConditions(); for (int j = 0; j < self()->getDependencyConditions()->getNumPostConditions(); ++j) { TR::RegisterDependency *dep = depGroup->getRegisterDependency(j); machine->setVirtualAssociatedWithReal(dep->getRealRegister(), dep->getRegister()); } machine->setGPRWeightsFromAssociations(); } } }