TR::Register * TR::AMD64SystemLinkage::buildIndirectDispatch(TR::Node *callNode) { TR::SymbolReference *methodSymRef = callNode->getSymbolReference(); TR_ASSERT(methodSymRef->getSymbol()->castToMethodSymbol()->isComputed(), "system linkage only supports computed indirect call for now %p\n", callNode); // Evaluate VFT // TR::Register *vftRegister; TR::Node *vftNode = callNode->getFirstChild(); if (vftNode->getRegister()) { vftRegister = vftNode->getRegister(); } else { vftRegister = cg()->evaluate(vftNode); } // Allocate adequate register dependencies. // // pre = number of argument registers + 1 for VFT register // post = number of volatile + VMThread + return register // uint32_t pre = getProperties().getNumIntegerArgumentRegisters() + getProperties().getNumFloatArgumentRegisters() + 1; uint32_t post = getProperties().getNumVolatileRegisters() + 1 + (callNode->getDataType() == TR::NoType ? 0 : 1); #if defined (PYTHON) && 0 // Treat all preserved GP regs as volatile until register map support available. // post += getProperties().getNumberOfPreservedGPRegisters(); #endif TR::RegisterDependencyConditions *callDeps = generateRegisterDependencyConditions(pre, 1, cg()); TR::RealRegister::RegNum scratchRegIndex = getProperties().getIntegerScratchRegister(1); callDeps->addPostCondition(vftRegister, scratchRegIndex, cg()); callDeps->stopAddingPostConditions(); // Evaluate outgoing arguments on the system stack and build pre-conditions. // int32_t memoryArgSize = buildArgs(callNode, callDeps); // Dispatch // generateRegInstruction(CALLReg, callNode, vftRegister, callDeps, cg()); cg()->resetIsLeafMethod(); // Build label post-conditions // TR::RegisterDependencyConditions *postDeps = generateRegisterDependencyConditions(0, post, cg()); TR::Register *returnReg = buildVolatileAndReturnDependencies(callNode, postDeps); postDeps->stopAddingPostConditions(); TR::LabelSymbol *postDepLabel = generateLabelSymbol(cg()); generateLabelInstruction(LABEL, callNode, postDepLabel, postDeps, cg()); return returnReg; }
static TR::Register *l2fd(TR::Node *node, TR::RealRegister *target, TR_X86OpCodes opRegMem8, TR_X86OpCodes opRegReg8, TR::CodeGenerator *cg) { TR::Node *child = node->getFirstChild(); TR::MemoryReference *tempMR; TR_ASSERT(cg->useSSEForSinglePrecision(), "assertion failure"); if (child->getRegister() == NULL && child->getReferenceCount() == 1 && child->getOpCode().isLoadVar()) { tempMR = generateX86MemoryReference(child, cg); generateRegMemInstruction(opRegMem8, node, target, tempMR, cg); tempMR->decNodeReferenceCounts(cg); } else { TR::Register *intReg = cg->evaluate(child); generateRegRegInstruction(opRegReg8, node, target, intReg, cg); cg->decReferenceCount(child); } node->setRegister(target); return target; }
static TR::Register *addOrSubInteger(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = cg->evaluate(firstChild); TR::Node *secondChild = node->getSecondChild(); TR::Register *trgReg = cg->allocateRegister(); bool isAdd = node->getOpCode().isAdd(); if (secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL) { int32_t value = secondChild->getInt(); if (constantIsUnsignedImm12(value)) { generateTrg1Src1ImmInstruction(cg, isAdd ? TR::InstOpCode::addimmw : TR::InstOpCode::subimmw, node, trgReg, src1Reg, value); } else { TR::Register *tmpReg = cg->allocateRegister(); loadConstant32(cg, node, value, tmpReg); generateTrg1Src2Instruction(cg, isAdd ? TR::InstOpCode::addw : TR::InstOpCode::subw, node, trgReg, src1Reg, tmpReg); cg->stopUsingRegister(tmpReg); } } else { TR::Register *src2Reg = cg->evaluate(secondChild); generateTrg1Src2Instruction(cg, isAdd ? TR::InstOpCode::addw : TR::InstOpCode::subw, node, trgReg, src1Reg, src2Reg); } node->setRegister(trgReg); firstChild->decReferenceCount(); secondChild->decReferenceCount(); return trgReg; }
TR::Register * OMR::ARM64::TreeEvaluator::lmulhEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = cg->evaluate(firstChild); TR::Node *secondChild = node->getSecondChild(); TR::Register *src2Reg; TR::Register *trgReg = cg->allocateRegister(); TR::Register *tmpReg = NULL; // lmulh is generated for constant ldiv and the second child is the magic number // assume magic number is usually a large odd number with little optimization opportunity if (secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL) { int64_t value = secondChild->getLongInt(); src2Reg = tmpReg = cg->allocateRegister(); loadConstant64(cg, node, value, src2Reg); } else { src2Reg = cg->evaluate(secondChild); } generateTrg1Src2Instruction(cg, TR::InstOpCode::smulh, node, trgReg, src1Reg, src2Reg); if (tmpReg) { cg->stopUsingRegister(tmpReg); } firstChild->decReferenceCount(); secondChild->decReferenceCount(); node->setRegister(trgReg); return trgReg; }
TR::Register * OMR::ARM64::TreeEvaluator::imulEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = cg->evaluate(firstChild); TR::Node *secondChild = node->getSecondChild(); TR::Register *trgReg; if (secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL) { int32_t value = secondChild->getInt(); if (value > 0 && cg->convertMultiplyToShift(node)) { // The multiply has been converted to a shift. trgReg = cg->evaluate(node); return trgReg; } else { trgReg = cg->allocateRegister(); mulConstant32(node, trgReg, src1Reg, value, cg); } } else { TR::Register *src2Reg = cg->evaluate(secondChild); trgReg = cg->allocateRegister(); generateMulInstruction(cg, node, trgReg, src1Reg, src2Reg); } firstChild->decReferenceCount(); secondChild->decReferenceCount(); node->setRegister(trgReg); return trgReg; }
TR::Node *TR_OutlinedInstructions::createOutlinedCallNode(TR::Node *callNode, TR::ILOpCodes callOp) { int32_t i; TR::Node *child; //We pass true for getSymbolReference because TR::Node *newCallNode = TR::Node::createWithSymRef(callNode, callOp, callNode->getNumChildren(), callNode->getSymbolReference()); newCallNode->setReferenceCount(1); for (i=0; i<callNode->getNumChildren(); i++) { child = callNode->getChild(i); if (child->getRegister() != NULL) { // Child has already been evaluated outside this tree. // newCallNode->setAndIncChild(i, child); } else if (child->getOpCode().isLoadConst()) { // Copy unevaluated constant nodes. // child = TR::Node::copy(child); child->setReferenceCount(1); newCallNode->setChild(i, child); } else { if ((child->getOpCodeValue() == TR::loadaddr) && /*(callNode->getOpCodeValue() == TR::instanceof || callNode->getOpCodeValue() == TR::checkcast || callNode->getOpCodeValue() == TR::checkcastAndNULLCHK || callNode->getOpCodeValue() == TR::New || callNode->getOpCodeValue() == TR::anewarray) &&*/ (child->getSymbolReference()->getSymbol()) && (child->getSymbolReference()->getSymbol()->getStaticSymbol())) { child = TR::Node::copy(child); child->setReferenceCount(1); newCallNode->setChild(i, child); } else { // Be very conservative at this point, even though it is possible to make it less so. For example, this will catch // the case of an unevaluated argument not persisting outside of the outlined region even though one of its subtrees will. // (void)_cg->evaluate(child); // Do not decrement the reference count here. It will be decremented when the call node is evaluated // again in the helper instruction stream. // newCallNode->setAndIncChild(i, child); } } } if(callNode->isPreparedForDirectJNI()) { newCallNode->setPreparedForDirectJNI(); } return newCallNode; }
void OMR::CodeGenerator::evaluateChildrenWithMultipleRefCount(TR::Node * node) { for (int i=0; i < node->getNumChildren(); i++) { TR::Node *child = node->getChild(i); if (child->getRegister() == NULL) // not already evaluated { // Note: we assume things without a symbol reference don't // necessarily need to be evaluated here, and can wait // until they are actually needed. // // vft pointers are speical - we need to evaluate the object in all cases // but for nopable virtual guards we can wait to load and mask the pointer // until we actually need to use it // if (child->getReferenceCount() > 1 && (child->getOpCode().hasSymbolReference() || (child->getOpCodeValue() == TR::l2a && child->getChild(0)->containsCompressionSequence()))) { TR::SymbolReference *vftPointerSymRef = TR::comp()->getSymRefTab()->element(TR::SymbolReferenceTable::vftSymbol); if (node->isNopableInlineGuard() && self()->getSupportsVirtualGuardNOPing() && child->getOpCodeValue() == TR::aloadi && child->getChild(0)->getOpCode().hasSymbolReference() && child->getChild(0)->getSymbolReference() == vftPointerSymRef && child->getChild(0)->getOpCodeValue() == TR::aloadi) { if (!child->getChild(0)->getChild(0)->getRegister() && child->getChild(0)->getChild(0)->getReferenceCount() > 1) self()->evaluate(child->getChild(0)->getChild(0)); else self()->evaluateChildrenWithMultipleRefCount(child->getChild(0)->getChild(0)); } else { self()->evaluate(child); } } else { self()->evaluateChildrenWithMultipleRefCount(child); } } } }
// TODO:AMD64: Could this be combined with istoreEvaluator without too much ugliness? TR::Register *OMR::X86::AMD64::TreeEvaluator::lstoreEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *valueChild; TR::Compilation* comp = cg->comp(); if (node->getOpCode().isIndirect()) valueChild = node->getSecondChild(); else valueChild = node->getFirstChild(); // Handle special cases // if (valueChild->getRegister() == NULL && valueChild->getReferenceCount() == 1) { // Special case storing a double value into long variable // if (valueChild->getOpCodeValue() == TR::dbits2l && !valueChild->normalizeNanValues()) { if (node->getOpCode().isIndirect()) { node->setChild(1, valueChild->getFirstChild()); TR::Node::recreate(node, TR::dstorei); TR::TreeEvaluator::floatingPointStoreEvaluator(node, cg); node->setChild(1, valueChild); TR::Node::recreate(node, TR::lstorei); } else { node->setChild(0, valueChild->getFirstChild()); TR::Node::recreate(node, TR::dstore); TR::TreeEvaluator::floatingPointStoreEvaluator(node, cg); node->setChild(0, valueChild); TR::Node::recreate(node, TR::lstore); } cg->decReferenceCount(valueChild); return NULL; } } return TR::TreeEvaluator::integerStoreEvaluator(node, cg); }
TR::Register * OMR::ARM64::TreeEvaluator::imulhEvaluator(TR::Node *node, TR::CodeGenerator *cg) { TR::Node *firstChild = node->getFirstChild(); TR::Register *src1Reg = cg->evaluate(firstChild); TR::Node *secondChild = node->getSecondChild(); TR::Register *src2Reg; TR::Register *trgReg = cg->allocateRegister(); TR::Register *tmpReg = NULL; TR::Register *zeroReg = cg->allocateRegister(); TR::RegisterDependencyConditions *cond = new (cg->trHeapMemory()) TR::RegisterDependencyConditions(1, 1, cg->trMemory()); addDependency(cond, zeroReg, TR::RealRegister::xzr, TR_GPR, cg); // imulh is generated for constant idiv and the second child is the magic number // assume magic number is usually a large odd number with little optimization opportunity if (secondChild->getOpCode().isLoadConst() && secondChild->getRegister() == NULL) { int32_t value = secondChild->getInt(); src2Reg = tmpReg = cg->allocateRegister(); loadConstant32(cg, node, value, src2Reg); } else { src2Reg = cg->evaluate(secondChild); } generateTrg1Src3Instruction(cg, TR::InstOpCode::smaddl, node, trgReg, src1Reg, src2Reg, zeroReg, cond); cg->stopUsingRegister(zeroReg); /* logical shift right by 32 bits */ uint32_t imm = 0x183F; // N=1, immr=32, imms=63 generateTrg1Src1ImmInstruction(cg, TR::InstOpCode::ubfmx, node, trgReg, trgReg, imm); if (tmpReg) { cg->stopUsingRegister(tmpReg); } firstChild->decReferenceCount(); secondChild->decReferenceCount(); node->setRegister(trgReg); return trgReg; }
int32_t OMR::CodeGenerator::getEvaluationPriority(TR::Node *node) { // Evaluation priority is the depth of the sub-tree. // int32_t nodePriority = 0; for (int32_t childCount = node->getNumChildren() - 1; childCount >= 0; childCount--) { TR::Node *child = node->getChild(childCount); int32_t childPriority; if (child->getRegister() != NULL) childPriority = 0; else childPriority = child->getEvaluationPriority(self()); if (childPriority >= nodePriority) nodePriority = childPriority + 1; } return nodePriority; }
void TR_S390BinaryAnalyser::genericAnalyser(TR::Node * root, TR::InstOpCode::Mnemonic regToRegOpCode, TR::InstOpCode::Mnemonic memToRegOpCode, TR::InstOpCode::Mnemonic copyOpCode) { TR::Node * firstChild; TR::Node * secondChild; firstChild = root->getFirstChild(); secondChild = root->getSecondChild(); TR::Register * firstRegister = firstChild->getRegister(); TR::Register * secondRegister = secondChild->getRegister(); TR::Compilation *comp = TR::comp(); TR::SymbolReference * firstReference = firstChild->getOpCode().hasSymbolReference() ? firstChild->getSymbolReference() : NULL; TR::SymbolReference * secondReference = secondChild->getOpCode().hasSymbolReference() ? secondChild->getSymbolReference() : NULL; setInputs(firstChild, firstRegister, secondChild, secondRegister, false, false, comp, (cg()->isAddressOfStaticSymRefWithLockedReg(firstReference) || cg()->isAddressOfPrivateStaticSymRefWithLockedReg(firstReference)), (cg()->isAddressOfStaticSymRefWithLockedReg(secondReference) || cg()->isAddressOfPrivateStaticSymRefWithLockedReg(secondReference))); /* * Check if SH or CH can be used to evaluate this integer subtract/compare node. * The second operand of SH/CH is a 16-bit number from memory. And using * these directly can save a load instruction. */ bool is16BitMemory2Operand = false; if (secondChild->getOpCodeValue() == TR::s2i && secondChild->getFirstChild()->getOpCodeValue() == TR::sloadi && secondChild->isSingleRefUnevaluated() && secondChild->getFirstChild()->isSingleRefUnevaluated()) { bool supported = true; if (memToRegOpCode == TR::InstOpCode::S) { memToRegOpCode = TR::InstOpCode::SH; } else if (memToRegOpCode == TR::InstOpCode::C) { memToRegOpCode = TR::InstOpCode::CH; } else { supported = false; } if (supported) { setMem2(); is16BitMemory2Operand = true; } } if (getEvalChild1()) { firstRegister = cg()->evaluate(firstChild); } if (getEvalChild2()) { secondRegister = cg()->evaluate(secondChild); } remapInputs(firstChild, firstRegister, secondChild, secondRegister); if (getCopyReg1()) { TR::Register * thirdReg; bool done = false; if (firstRegister->getKind() == TR_GPR64) { thirdReg = cg()->allocate64bitRegister(); } else if (firstRegister->getKind() == TR_VRF) { TR_ASSERT(false,"VRF: genericAnalyser unimplemented"); } else if (firstRegister->getKind() != TR_FPR && firstRegister->getKind() != TR_VRF) { thirdReg = cg()->allocateRegister(); } else { thirdReg = cg()->allocateRegister(TR_FPR); } if (cg()->getS390ProcessorInfo()->supportsArch(TR_S390ProcessorInfo::TR_z196)) { if (getBinaryReg3Reg2() || secondRegister != NULL) { if (regToRegOpCode == TR::InstOpCode::SR) { generateRRRInstruction(cg(), TR::InstOpCode::SRK, root, thirdReg, firstRegister, secondRegister); done = true; } else if (regToRegOpCode == TR::InstOpCode::SLR) { generateRRRInstruction(cg(), TR::InstOpCode::SLRK, root, thirdReg, firstRegister, secondRegister); done = true; } else if (regToRegOpCode == TR::InstOpCode::SGR) { generateRRRInstruction(cg(), TR::InstOpCode::SGRK, root, thirdReg, firstRegister, secondRegister); done = true; } else if (regToRegOpCode == TR::InstOpCode::SLGR) { generateRRRInstruction(cg(), TR::InstOpCode::SLGRK, root, thirdReg, firstRegister, secondRegister); done = true; } } } if (!done) { generateRRInstruction(cg(), copyOpCode, root, thirdReg, firstRegister); if (getBinaryReg3Reg2() || (secondRegister != NULL)) { generateRRInstruction(cg(), regToRegOpCode, root, thirdReg, secondRegister); } else { TR::Node* loadBaseAddr = is16BitMemory2Operand ? secondChild->getFirstChild() : secondChild; TR::MemoryReference * tempMR = generateS390MemoryReference(loadBaseAddr, cg()); //floating-point arithmatics don't have RXY format instructions, so no long displacement if (secondChild->getOpCode().isFloatingPoint()) { tempMR->enforce4KDisplacementLimit(secondChild, cg(), NULL); } generateRXInstruction(cg(), memToRegOpCode, root, thirdReg, tempMR); tempMR->stopUsingMemRefRegister(cg()); if (is16BitMemory2Operand) { cg()->decReferenceCount(secondChild->getFirstChild()); } } } root->setRegister(thirdReg); } else if (getBinaryReg1Reg2()) { generateRRInstruction(cg(), regToRegOpCode, root, firstRegister, secondRegister); root->setRegister(firstRegister); } else // assert getBinaryReg1Mem2() == true { TR_ASSERT( !getInvalid(), "TR_S390BinaryAnalyser::invalid case\n"); TR::MemoryReference * tempMR = generateS390MemoryReference(is16BitMemory2Operand ? secondChild->getFirstChild() : secondChild, cg()); //floating-point arithmatics don't have RXY format instructions, so no long displacement if (secondChild->getOpCode().isFloatingPoint()) { tempMR->enforce4KDisplacementLimit(secondChild, cg(), NULL); } generateRXInstruction(cg(), memToRegOpCode, root, firstRegister, tempMR); tempMR->stopUsingMemRefRegister(cg()); if (is16BitMemory2Operand) cg()->decReferenceCount(secondChild->getFirstChild()); root->setRegister(firstRegister); } cg()->decReferenceCount(firstChild); cg()->decReferenceCount(secondChild); return; }
void TR_S390BinaryAnalyser::longSubtractAnalyser(TR::Node * root) { TR::Node * firstChild; TR::Node * secondChild; TR::Instruction * cursor = NULL; TR::RegisterDependencyConditions * dependencies = NULL; bool setsOrReadsCC = NEED_CC(root) || (root->getOpCodeValue() == TR::lusubb); TR::InstOpCode::Mnemonic regToRegOpCode; TR::InstOpCode::Mnemonic memToRegOpCode; TR::Compilation *comp = TR::comp(); if (TR::Compiler->target.is64Bit() || cg()->use64BitRegsOn32Bit()) { if (!setsOrReadsCC) { regToRegOpCode = TR::InstOpCode::SGR; memToRegOpCode = TR::InstOpCode::SG; } else { regToRegOpCode = TR::InstOpCode::SLGR; memToRegOpCode = TR::InstOpCode::SLG; } } else { regToRegOpCode = TR::InstOpCode::SLR; memToRegOpCode = TR::InstOpCode::SL; } firstChild = root->getFirstChild(); secondChild = root->getSecondChild(); TR::Register * firstRegister = firstChild->getRegister(); TR::Register * secondRegister = secondChild->getRegister(); setInputs(firstChild, firstRegister, secondChild, secondRegister, false, false, comp); /** Attempt to use SGH to subtract halfword (64 <- 16). * The second child is a halfword from memory */ bool is16BitMemory2Operand = false; if (TR::Compiler->target.cpu.getS390SupportsZ14() && secondChild->getOpCodeValue() == TR::s2l && secondChild->getFirstChild()->getOpCodeValue() == TR::sloadi && secondChild->isSingleRefUnevaluated() && secondChild->getFirstChild()->isSingleRefUnevaluated()) { setMem2(); memToRegOpCode = TR::InstOpCode::SGH; is16BitMemory2Operand = true; } if (getEvalChild1()) { firstRegister = cg()->evaluate(firstChild); } if (getEvalChild2()) { secondRegister = cg()->evaluate(secondChild); } remapInputs(firstChild, firstRegister, secondChild, secondRegister); if ((root->getOpCodeValue() == TR::lusubb) && TR_S390ComputeCC::setCarryBorrow(root->getChild(2), false, cg())) { // use SLBGR rather than SLGR/SGR // SLBG rather than SLG/SG // or // use SLBR rather than SLR // SLB rather than SL bool uses64bit = TR::Compiler->target.is64Bit() || cg()->use64BitRegsOn32Bit(); regToRegOpCode = uses64bit ? TR::InstOpCode::SLBGR : TR::InstOpCode::SLBR; memToRegOpCode = uses64bit ? TR::InstOpCode::SLBG : TR::InstOpCode::SLB; } if (TR::Compiler->target.is64Bit() || cg()->use64BitRegsOn32Bit()) { if (getCopyReg1()) { TR::Register * thirdReg = cg()->allocate64bitRegister(); root->setRegister(thirdReg); generateRRInstruction(cg(), TR::InstOpCode::LGR, root, thirdReg, firstRegister); if (getBinaryReg3Reg2()) { generateRRInstruction(cg(), regToRegOpCode, root, thirdReg, secondRegister); } else // assert getBinaryReg3Mem2() == true { TR::MemoryReference * longMR = generateS390MemoryReference(secondChild, cg()); generateRXInstruction(cg(), memToRegOpCode, root, thirdReg, longMR); longMR->stopUsingMemRefRegister(cg()); } } else if (getBinaryReg1Reg2()) { generateRRInstruction(cg(), regToRegOpCode, root, firstRegister, secondRegister); root->setRegister(firstRegister); } else // assert getBinaryReg1Mem2() == true { TR_ASSERT( !getInvalid(), "TR_S390BinaryAnalyser::invalid case\n"); TR::Node* baseAddrNode = is16BitMemory2Operand ? secondChild->getFirstChild() : secondChild; TR::MemoryReference * longMR = generateS390MemoryReference(baseAddrNode, cg()); generateRXInstruction(cg(), memToRegOpCode, root, firstRegister, longMR); longMR->stopUsingMemRefRegister(cg()); root->setRegister(firstRegister); if(is16BitMemory2Operand) { cg()->decReferenceCount(secondChild->getFirstChild()); } } } else // if 32bit codegen... { bool zArchTrexsupported = performTransformation(comp, "O^O Use SL/SLB for long sub."); TR::Register * highDiff = NULL; TR::LabelSymbol * doneLSub = TR::LabelSymbol::create(cg()->trHeapMemory(),cg()); if (getCopyReg1()) { TR::Register * lowThird = cg()->allocateRegister(); TR::Register * highThird = cg()->allocateRegister(); TR::RegisterPair * thirdReg = cg()->allocateConsecutiveRegisterPair(lowThird, highThird); highDiff = highThird; dependencies = new (cg()->trHeapMemory()) TR::RegisterDependencyConditions(0, 9, cg()); dependencies->addPostCondition(firstRegister, TR::RealRegister::EvenOddPair); dependencies->addPostCondition(firstRegister->getHighOrder(), TR::RealRegister::LegalEvenOfPair); dependencies->addPostCondition(firstRegister->getLowOrder(), TR::RealRegister::LegalOddOfPair); // If 2nd operand has ref count of 1 and can be accessed by a memory reference, // then second register will not be used. if(secondRegister == firstRegister && !setsOrReadsCC) { TR_ASSERT( false, "lsub with identical children - fix Simplifier"); } if (secondRegister != NULL && firstRegister != secondRegister) { dependencies->addPostCondition(secondRegister, TR::RealRegister::EvenOddPair); dependencies->addPostCondition(secondRegister->getHighOrder(), TR::RealRegister::LegalEvenOfPair); dependencies->addPostCondition(secondRegister->getLowOrder(), TR::RealRegister::LegalOddOfPair); } dependencies->addPostCondition(highThird, TR::RealRegister::AssignAny); root->setRegister(thirdReg); generateRRInstruction(cg(), TR::InstOpCode::LR, root, highThird, firstRegister->getHighOrder()); generateRRInstruction(cg(), TR::InstOpCode::LR, root, lowThird, firstRegister->getLowOrder()); if (getBinaryReg3Reg2()) { if ((ENABLE_ZARCH_FOR_32 && zArchTrexsupported) || setsOrReadsCC) { generateRRInstruction(cg(), regToRegOpCode, root, lowThird, secondRegister->getLowOrder()); generateRRInstruction(cg(), TR::InstOpCode::SLBR, root, highThird, secondRegister->getHighOrder()); } else { generateRRInstruction(cg(), TR::InstOpCode::SR, root, highThird, secondRegister->getHighOrder()); generateRRInstruction(cg(), TR::InstOpCode::SLR, root, lowThird, secondRegister->getLowOrder()); } } else // assert getBinaryReg3Mem2() == true { TR::MemoryReference * highMR = generateS390MemoryReference(secondChild, cg()); TR::MemoryReference * lowMR = generateS390MemoryReference(*highMR, 4, cg()); dependencies->addAssignAnyPostCondOnMemRef(highMR); if ((ENABLE_ZARCH_FOR_32 && zArchTrexsupported) || setsOrReadsCC) { generateRXInstruction(cg(), memToRegOpCode, root, lowThird, lowMR); generateRXInstruction(cg(), TR::InstOpCode::SLB, root, highThird, highMR); } else { generateRXInstruction(cg(), TR::InstOpCode::S, root, highThird, highMR); generateRXInstruction(cg(), TR::InstOpCode::SL, root, lowThird, lowMR); } highMR->stopUsingMemRefRegister(cg()); lowMR->stopUsingMemRefRegister(cg()); } } else if (getBinaryReg1Reg2()) { dependencies = new (cg()->trHeapMemory()) TR::RegisterDependencyConditions(0, 6, cg()); dependencies->addPostCondition(firstRegister, TR::RealRegister::EvenOddPair); dependencies->addPostCondition(firstRegister->getHighOrder(), TR::RealRegister::LegalEvenOfPair); dependencies->addPostCondition(firstRegister->getLowOrder(), TR::RealRegister::LegalOddOfPair); if(secondRegister == firstRegister) { TR_ASSERT( false, "lsub with identical children - fix Simplifier"); } if (secondRegister != firstRegister) { dependencies->addPostCondition(secondRegister, TR::RealRegister::EvenOddPair); dependencies->addPostCondition(secondRegister->getHighOrder(), TR::RealRegister::LegalEvenOfPair); dependencies->addPostCondition(secondRegister->getLowOrder(), TR::RealRegister::LegalOddOfPair); } if ((ENABLE_ZARCH_FOR_32 && zArchTrexsupported) || setsOrReadsCC) { generateRRInstruction(cg(), regToRegOpCode, root, firstRegister->getLowOrder(), secondRegister->getLowOrder()); generateRRInstruction(cg(), TR::InstOpCode::SLBR, root, firstRegister->getHighOrder(), secondRegister->getHighOrder()); } else { generateRRInstruction(cg(), TR::InstOpCode::SR, root, firstRegister->getHighOrder(), secondRegister->getHighOrder()); generateRRInstruction(cg(), TR::InstOpCode::SLR, root, firstRegister->getLowOrder(), secondRegister->getLowOrder()); } highDiff = firstRegister->getHighOrder(); root->setRegister(firstRegister); } else // assert getBinaryReg1Mem2() == true { TR_ASSERT( !getInvalid(),"TR_S390BinaryAnalyser::invalid case\n"); dependencies = new (cg()->trHeapMemory()) TR::RegisterDependencyConditions(0, 5, cg()); dependencies->addPostCondition(firstRegister, TR::RealRegister::EvenOddPair); dependencies->addPostCondition(firstRegister->getHighOrder(), TR::RealRegister::LegalEvenOfPair); dependencies->addPostCondition(firstRegister->getLowOrder(), TR::RealRegister::LegalOddOfPair); TR::MemoryReference * highMR = generateS390MemoryReference(secondChild, cg()); TR::MemoryReference * lowMR = generateS390MemoryReference(*highMR, 4, cg()); dependencies->addAssignAnyPostCondOnMemRef(highMR); if ((ENABLE_ZARCH_FOR_32 && zArchTrexsupported) || setsOrReadsCC) { generateRXInstruction(cg(), memToRegOpCode, root, firstRegister->getLowOrder(), lowMR); generateRXInstruction(cg(), TR::InstOpCode::SLB, root, firstRegister->getHighOrder(), highMR); } else { generateRXInstruction(cg(), TR::InstOpCode::S, root, firstRegister->getHighOrder(), highMR); generateRXInstruction(cg(), TR::InstOpCode::SL, root, firstRegister->getLowOrder(), lowMR); } highDiff = firstRegister->getHighOrder(); root->setRegister(firstRegister); highMR->stopUsingMemRefRegister(cg()); lowMR->stopUsingMemRefRegister(cg()); } if (!((ENABLE_ZARCH_FOR_32 && zArchTrexsupported) || setsOrReadsCC)) { // Check for overflow in LS int. If overflow, we are done. generateS390BranchInstruction(cg(), TR::InstOpCode::BRC,TR::InstOpCode::COND_MASK3, root, doneLSub); // Increment MS int due to overflow in LS int generateRIInstruction(cg(), TR::InstOpCode::AHI, root, highDiff, -1); generateS390LabelInstruction(cg(), TR::InstOpCode::LABEL, root, doneLSub, dependencies); } } cg()->decReferenceCount(firstChild); cg()->decReferenceCount(secondChild); return; }
TR::Register * OMR::CodeGenerator::evaluate(TR::Node * node) { TR::Register *reg; bool trace = self()->comp()->getOptions()->getTraceCGOption(TR_TraceCGEvaluation); TR::ILOpCodes opcode = node->getOpCodeValue(); TR_ASSERT(!self()->comp()->getOption(TR_EnableParanoidRefCountChecks) || node->getOpCode().isTreeTop() || node->getReferenceCount() > 0, "OMR::CodeGenerator::evaluate invoked for nontreetop node [%s] with count == 0", node->getName(self()->comp()->getDebug())); if (opcode != TR::BBStart && node->getRegister()) { reg = node->getRegister(); if (trace) { self()->getDebug()->printNodeEvaluation(node, ": ", reg); } } else { if (trace) { self()->getDebug()->printNodeEvaluation(node); _indentation += 2; } // Evaluation of a TR IL tree can be performed by many functions: // // 1) evaluate(...) // 2) populateMemoryReference(...) // 3) populateAddTree(...) // ... // // However all of these functions can be categorized into two classes: // // A) functions which completely evaluate their subtree. // B) functions which partially evaluate their subtree. // // Because functions of class A and class B can be used interchangably to // perform a recursive decent of a TR IL tree, and because A or B functions // can perform a destructive evaluation of their subtree, a bug can occur where // the results of a partial evalutation are destructively overwritten before // being completely evalutated. // // Ex: the motivating case is the following evaluation pattern: // // node_A evaluate // node_B populateMemoryReference // node_C evaluate // // where // // a) there is a common node between the subtrees of node_B and node_C. // b) calling populateMemoryReference on node_B reduces the reference count of one // of the base or index nodes to 1, creating the "opportunity" for a destructive // evaluation. // // The following chain of events occurs: // // 1) evaluate is called on node_A. This evaluator can produce instructions of RX form, // and chooses to do so for this node. // // 2) populateMemoryReference is called on node_B, and evaluates the subtree, returning // a TR_MemoryReference to node_A's evaluator. This memory reference has not been // dereferenced yet, and the base (and optionally index) nodes may have registers // assigned to them. // // 3) evaluate is called on node_C, which chooses to destructively evaluate the commoned // base node. The memory reference's base register now contains a garbage value. // // 4) control passes to node_A's evaluator, which emits an RX instruction using node_B's // memory reference and node_C's register. // // In the past, the fix for this was to switch the order of evaluation: call evaluate // on node_C and then call populateMemoryReference on node_B. This fixes this scenario, but // the capability of another tree and evaluation pattern to create this bug still exists. // // As well, more insidious trees exist: // // ificmpeq // iiload // i2l // x // iiload // ishl // ==> i2l // 4 // // The evaluation pattern here could be: // // evaluate // populateMemoryReference // evaluate // populateMemoryReference // evaluate // // If the commoned node's reference count is 2 coming into ificmpeq's evaluator, then // the second sub-evaluate call could be destructive to the first populateMemoryReference. // // Even worse, if either subtree could be destructive, then there would be no correct order to // perform the function calls: // // ificmpeq // iiload // ishl // ==> x // 7 // iiload // ishl // ==> x // 4 // // Generally, two conditions must be true for this bug to be possible: // // 1) the following two classes of recursive decent functions must exist: // A) functions which completely evaluate their subtree. // B) functions which partially evaluate their subtree. // // 2) destructive evaluation by either class of function must be possible. // // This code implements changes to eliminate the second condition for this bug by performing // the following check and fixup: // // If in a function which partially evaluates its subtree, note all non-restricted nodes that // have a reference count > 1. If any of those node's reference counts reach 1, then artificially // inflate those reference counts by 1 for the lifetime of the parent evaluation. // int32_t topOfNodeStackBeforeEvaluation = _stackOfArtificiallyInflatedNodes.topIndex(); // Memory references are not like registers, and should not be allowed to escape their evaluator. // Explicitly note memory references that are not loaded into registers and automatically call // stopUsingMemRefRegister on all memory references that have "escaped". // // Only the s390 memory references are tracked in this way. // int32_t topOfMemRefStackBeforeEvaluation = _stackOfMemoryReferencesCreatedDuringEvaluation.topIndex(); reg = _nodeToInstrEvaluators[opcode](node, self()); if (self()->comp()->getOptions()->getTraceCGOption(TR_TraceCGEvaluation)) { self()->getDebug()->printNodeEvaluation(node, "<- ", reg, false); _indentation -= 2; } if (self()->comp()->getOption(TR_TraceRegisterPressureDetails)) { traceMsg(self()->comp(), " evaluated %s", self()->getDebug()->getName(node)); self()->getDebug()->dumpLiveRegisters(); traceMsg(self()->comp(), "\n"); } // Pop off and decrement tracked nodes // while (_stackOfArtificiallyInflatedNodes.topIndex() > topOfNodeStackBeforeEvaluation) { TR::Node * artificiallyInflatedNode = _stackOfArtificiallyInflatedNodes.pop(); if (artificiallyInflatedNode->getReferenceCount() == 1) { // When inflating reference counts, two cases exist: // // 1) N's ref count reaches 1 in a populate* call, which is then inc'ed to 2. // // 1a) N is never evaluated, so the ref count never goes down to 1. (node was not commoned in another subtree) // // - no tree difference should be seen in this case. // // 1b) N is evaluated, so the ref count then goes down to 1. (node was commoned in another subtree) // // - register shuffling _could_ be seen in this case. // - but a bug might have been avoided: partial and complete evaluation of a commoned node occurred. // if (self()->comp()->getOption(TR_TraceCG)) { self()->comp()->getDebug()->trace(" _stackOfArtificiallyInflatedNodes.pop(): node %p part of commoned case, might have avoided a bug!\n", artificiallyInflatedNode); } } self()->decReferenceCount(artificiallyInflatedNode); #ifdef J9_PROJECT_SPECIFIC #if defined(TR_TARGET_S390) if (artificiallyInflatedNode->getOpaquePseudoRegister()) { TR_OpaquePseudoRegister *reg = artificiallyInflatedNode->getOpaquePseudoRegister(); TR_StorageReference *ref = reg->getStorageReference(); self()->processUnusedStorageRef(ref); } #endif #endif if (self()->comp()->getOption(TR_TraceCG)) { self()->comp()->getDebug()->trace(" _stackOfArtificiallyInflatedNodes.pop() %p, decReferenceCount(...) called. reg=%s\n", artificiallyInflatedNode, artificiallyInflatedNode->getRegister()?artificiallyInflatedNode->getRegister()->getRegisterName(self()->comp()):"null"); } } #if defined(TR_TARGET_S390) self()->StopUsingEscapedMemRefsRegisters(topOfMemRefStackBeforeEvaluation); #endif bool checkRefCount = (node->getReferenceCount() <= 1 || (reg && reg == node->getRegister())); // for anchor mode, if node is an indirect store, it can have // ref count <= 2 // but for compressedRefs, the indirect store must be an address if (self()->comp()->useAnchors()) { if (((node->getOpCode().isStoreIndirect() && (self()->comp()->useCompressedPointers() && (node->getSymbolReference()->getSymbol()->getDataType() == TR::Address))) || opcode == TR::wrtbari) && node->getReferenceCount() <= 2 && !checkRefCount) checkRefCount = true; } TR_ASSERT(checkRefCount, "evaluate: the node's register wasn't set (node [%s])", node->getName(self()->comp()->getDebug())); } return reg; }
// 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; }
TR::Register * TR::AMD64SystemLinkage::buildVolatileAndReturnDependencies( TR::Node *callNode, TR::RegisterDependencyConditions *deps) { if (callNode->getOpCode().isIndirect()) { TR::Node *vftChild = callNode->getFirstChild(); if (vftChild->getRegister() && (vftChild->getReferenceCount() > 1)) { } else { // VFT child dies here; decrement it early so it doesn't interfere with dummy regs. cg()->recursivelyDecReferenceCount(vftChild); } } TR_ASSERT(deps != NULL, "expected register dependencies"); // Figure out which is the return register. // TR::RealRegister::RegNum returnRegIndex; TR_RegisterKinds returnKind; switch (callNode->getDataType()) { case TR::NoType: returnRegIndex = TR::RealRegister::NoReg; returnKind = TR_NoRegister; break; case TR::Int8: case TR::Int16: case TR::Int32: case TR::Int64: case TR::Address: returnRegIndex = getProperties().getIntegerReturnRegister(); returnKind = TR_GPR; break; case TR::Float: case TR::Double: returnRegIndex = getProperties().getFloatReturnRegister(); returnKind = TR_FPR; break; case TR::Aggregate: default: TR_ASSERT(false, "Unrecognized call node data type: #%d", (int)callNode->getDataType()); break; } // Kill all non-preserved int and float regs besides the return register. // int32_t i; TR::RealRegister::RegNum scratchIndex = getProperties().getIntegerScratchRegister(1); for (i=0; i<getProperties().getNumVolatileRegisters(); i++) { TR::RealRegister::RegNum regIndex = getProperties()._volatileRegisters[i]; if (regIndex != returnRegIndex) { TR_RegisterKinds rk = (i < getProperties()._numberOfVolatileGPRegisters) ? TR_GPR : TR_FPR; TR::Register *dummy = cg()->allocateRegister(rk); deps->addPostCondition(dummy, regIndex, cg()); // Note that we don't setPlaceholderReg here. If this volatile reg is also volatile // in the caller's linkage, then that flag doesn't matter much anyway. If it's preserved // in the caller's linkage, then we don't want to set that flag because we want this // use of the register to count as a "real" use, thereby motivating the prologue to // preserve the register. // A scratch register is necessary to call the native without a trampoline. // if (callNode->getOpCode().isIndirect() || (regIndex != scratchIndex)) cg()->stopUsingRegister(dummy); } } #if defined (PYTHON) && 0 // Evict the preserved registers across the call // for (i=0; i<getProperties().getNumberOfPreservedGPRegisters(); i++) { TR::RealRegister::RegNum regIndex = getProperties()._preservedRegisters[i]; TR::Register *dummy = cg()->allocateRegister(TR_GPR); deps->addPostCondition(dummy, regIndex, cg()); // Note that we don't setPlaceholderReg here. If this volatile reg is also volatile // in the caller's linkage, then that flag doesn't matter much anyway. If it's preserved // in the caller's linkage, then we don't want to set that flag because we want this // use of the register to count as a "real" use, thereby motivating the prologue to // preserve the register. // A scratch register is necessary to call the native without a trampoline. // if (callNode->getOpCode().isIndirect() || (regIndex != scratchIndex)) cg()->stopUsingRegister(dummy); } #endif if (callNode->getOpCode().isIndirect()) { TR::Node *vftChild = callNode->getFirstChild(); if (vftChild->getRegister() && (vftChild->getReferenceCount() > 1)) { // VFT child survives the call, so we must include it in the postconditions. deps->addPostCondition(vftChild->getRegister(), TR::RealRegister::NoReg, cg()); cg()->recursivelyDecReferenceCount(vftChild); } } // Now that everything is dead, we can allocate the return register without // interference // TR::Register *returnRegister; if (returnRegIndex) { TR_ASSERT(returnKind != TR_NoRegister, "assertion failure"); if (callNode->getDataType() == TR::Address) returnRegister = cg()->allocateCollectedReferenceRegister(); else { returnRegister = cg()->allocateRegister(returnKind); if (callNode->getDataType() == TR::Float) returnRegister->setIsSinglePrecision(); } deps->addPostCondition(returnRegister, returnRegIndex, cg()); } else returnRegister = NULL; // The reg dependency is left open intentionally, and need to be closed by // the caller. The reason is because, child class might call this method, while // adding more register dependecies; if we close the reg dependency here, // the child class won't be able to add more register dependencies. return returnRegister; }
OMR::Power::RegisterDependencyConditions::RegisterDependencyConditions( TR::CodeGenerator *cg, TR::Node *node, uint32_t extranum, TR::Instruction **cursorPtr) { List<TR::Register> regList(cg->trMemory()); TR::Instruction *iCursor = (cursorPtr==NULL)?NULL:*cursorPtr; int32_t totalNum = node->getNumChildren() + extranum; int32_t i; cg->comp()->incVisitCount(); int32_t numLongs = 0; // // Pre-compute how many longs are global register candidates // for (i = 0; i < node->getNumChildren(); ++i) { TR::Node *child = node->getChild(i); TR::Register *reg = child->getRegister(); if (reg!=NULL /* && reg->getKind()==TR_GPR */) { if (child->getHighGlobalRegisterNumber() > -1) numLongs++; } } totalNum = totalNum + numLongs; _preConditions = new (totalNum, cg->trMemory()) TR_PPCRegisterDependencyGroup; _postConditions = new (totalNum, cg->trMemory()) TR_PPCRegisterDependencyGroup; _numPreConditions = totalNum; _addCursorForPre = 0; _numPostConditions = totalNum; _addCursorForPost = 0; // First, handle dependencies that match current association for (i=0; i<node->getNumChildren(); i++) { TR::Node *child = node->getChild(i); TR::Register *reg = child->getRegister(); TR::Register *highReg = NULL; TR::RealRegister::RegNum regNum = (TR::RealRegister::RegNum)cg->getGlobalRegister(child->getGlobalRegisterNumber()); TR::RealRegister::RegNum highRegNum; if (child->getHighGlobalRegisterNumber() > -1) { highRegNum = (TR::RealRegister::RegNum)cg->getGlobalRegister(child->getHighGlobalRegisterNumber()); TR::RegisterPair *regPair = reg->getRegisterPair(); TR_ASSERT(regPair, "assertion failure"); highReg = regPair->getHighOrder(); reg = regPair->getLowOrder(); if (highReg->getAssociation() != highRegNum || reg->getAssociation() != regNum) continue; } else if (reg->getAssociation() != regNum) continue; TR_ASSERT(!regList.find(reg) && (!highReg || !regList.find(highReg)), "Should not happen\n"); addPreCondition(reg, regNum); addPostCondition(reg, regNum); regList.add(reg); if (highReg) { addPreCondition(highReg, highRegNum); addPostCondition(highReg, highRegNum); regList.add(highReg); } } // Second pass to handle dependencies for which association does not exist // or does not match for (i=0; i<node->getNumChildren(); i++) { TR::Node *child = node->getChild(i); TR::Register *reg = child->getRegister(); TR::Register *highReg = NULL; TR::Register *copyReg = NULL; TR::Register *highCopyReg = NULL; TR::RealRegister::RegNum regNum = (TR::RealRegister::RegNum)cg->getGlobalRegister(child->getGlobalRegisterNumber()); TR::RealRegister::RegNum highRegNum; if (child->getHighGlobalRegisterNumber() > -1) { highRegNum = (TR::RealRegister::RegNum)cg->getGlobalRegister(child->getHighGlobalRegisterNumber()); TR::RegisterPair *regPair = reg->getRegisterPair(); TR_ASSERT(regPair, "assertion failure"); highReg = regPair->getHighOrder(); reg = regPair->getLowOrder(); if (highReg->getAssociation() == highRegNum && reg->getAssociation() == regNum) continue; } else if (reg->getAssociation() == regNum) continue; if (regList.find(reg) || (highReg && regList.find(highReg))) { TR::InstOpCode::Mnemonic opCode; TR_RegisterKinds kind = reg->getKind(); switch (kind) { case TR_GPR: opCode = TR::InstOpCode::mr; break; case TR_FPR: opCode = TR::InstOpCode::fmr; break; case TR_VRF: opCode = TR::InstOpCode::vor; //TR_ASSERT(0, "VMX not fully supported."); break; case TR_VSX_VECTOR: opCode = TR::InstOpCode::xxlor; break; case TR_CCR: opCode = TR::InstOpCode::mcrf; break; default: TR_ASSERT(0, "Invalid register kind."); } if (regList.find(reg)) { bool containsInternalPointer = false; if (reg->getPinningArrayPointer()) containsInternalPointer = true; copyReg = (reg->containsCollectedReference() && !containsInternalPointer) ? cg->allocateCollectedReferenceRegister() : cg->allocateRegister(kind); if (containsInternalPointer) { copyReg->setContainsInternalPointer(); copyReg->setPinningArrayPointer(reg->getPinningArrayPointer()); } if (opCode == TR::InstOpCode::vor || opCode == TR::InstOpCode::xxlor) iCursor = generateTrg1Src2Instruction(cg, opCode, node, copyReg, reg, reg, iCursor); else iCursor = generateTrg1Src1Instruction(cg, opCode, node, copyReg, reg, iCursor); reg = copyReg; } if (highReg && regList.find(highReg)) { bool containsInternalPointer = false; if (highReg->getPinningArrayPointer()) containsInternalPointer = true; highCopyReg = (highReg->containsCollectedReference() && !containsInternalPointer) ? cg->allocateCollectedReferenceRegister() : cg->allocateRegister(kind); if (containsInternalPointer) { highCopyReg->setContainsInternalPointer(); highCopyReg->setPinningArrayPointer(highReg->getPinningArrayPointer()); } if (opCode == TR::InstOpCode::vor || opCode == TR::InstOpCode::xxlor) iCursor = generateTrg1Src2Instruction(cg, opCode, node, highCopyReg, highReg, highReg, iCursor); else iCursor = generateTrg1Src1Instruction(cg, opCode, node, highCopyReg, highReg, iCursor); highReg = highCopyReg; } } addPreCondition(reg, regNum); addPostCondition(reg, regNum); if (copyReg != NULL) cg->stopUsingRegister(copyReg); else regList.add(reg); if (highReg) { addPreCondition(highReg, highRegNum); addPostCondition(highReg, highRegNum); if (highCopyReg != NULL) cg->stopUsingRegister(highCopyReg); else regList.add(highReg); } } if (iCursor!=NULL && cursorPtr!=NULL) *cursorPtr = iCursor; }