int32_t TR::ARM64SystemLinkage::buildArgs(TR::Node *callNode, TR::RegisterDependencyConditions *dependencies) { const TR::ARM64LinkageProperties &properties = getProperties(); TR::ARM64MemoryArgument *pushToMemory = NULL; TR::Register *argMemReg; TR::Register *tempReg; int32_t argIndex = 0; int32_t numMemArgs = 0; int32_t argSize = 0; int32_t numIntegerArgs = 0; int32_t numFloatArgs = 0; int32_t totalSize; int32_t i; TR::Node *child; TR::DataType childType; TR::DataType resType = callNode->getType(); uint32_t firstArgumentChild = callNode->getFirstArgumentIndex(); /* Step 1 - figure out how many arguments are going to be spilled to memory i.e. not in registers */ for (i = firstArgumentChild; i < callNode->getNumChildren(); i++) { child = callNode->getChild(i); childType = child->getDataType(); switch (childType) { case TR::Int8: case TR::Int16: case TR::Int32: case TR::Int64: case TR::Address: if (numIntegerArgs >= properties.getNumIntArgRegs()) numMemArgs++; numIntegerArgs++; break; case TR::Float: case TR::Double: if (numFloatArgs >= properties.getNumFloatArgRegs()) numMemArgs++; numFloatArgs++; break; default: TR_ASSERT(false, "Argument type %s is not supported\n", childType.toString()); } } // From here, down, any new stack allocations will expire / die when the function returns TR::StackMemoryRegion stackMemoryRegion(*trMemory()); /* End result of Step 1 - determined number of memory arguments! */ if (numMemArgs > 0) { pushToMemory = new (trStackMemory()) TR::ARM64MemoryArgument[numMemArgs]; argMemReg = cg()->allocateRegister(); } totalSize = numMemArgs * 8; // align to 16-byte boundary totalSize = (totalSize + 15) & (~15); numIntegerArgs = 0; numFloatArgs = 0; for (i = firstArgumentChild; i < callNode->getNumChildren(); i++) { TR::MemoryReference *mref = NULL; TR::Register *argRegister; TR::InstOpCode::Mnemonic op; child = callNode->getChild(i); childType = child->getDataType(); switch (childType) { case TR::Int8: case TR::Int16: case TR::Int32: case TR::Int64: case TR::Address: if (childType == TR::Address) argRegister = pushAddressArg(child); else if (childType == TR::Int64) argRegister = pushLongArg(child); else argRegister = pushIntegerWordArg(child); if (numIntegerArgs < properties.getNumIntArgRegs()) { if (!cg()->canClobberNodesRegister(child, 0)) { if (argRegister->containsCollectedReference()) tempReg = cg()->allocateCollectedReferenceRegister(); else tempReg = cg()->allocateRegister(); generateMovInstruction(cg(), callNode, tempReg, argRegister); argRegister = tempReg; } if (numIntegerArgs == 0 && (resType.isAddress() || resType.isInt32() || resType.isInt64())) { TR::Register *resultReg; if (resType.isAddress()) resultReg = cg()->allocateCollectedReferenceRegister(); else resultReg = cg()->allocateRegister(); dependencies->addPreCondition(argRegister, TR::RealRegister::x0); dependencies->addPostCondition(resultReg, TR::RealRegister::x0); } else { addDependency(dependencies, argRegister, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg()); } } else { // numIntegerArgs >= properties.getNumIntArgRegs() if (childType == TR::Address || childType == TR::Int64) { op = TR::InstOpCode::strpostx; } else { op = TR::InstOpCode::strpostw; } mref = getOutgoingArgumentMemRef(argMemReg, argRegister, op, pushToMemory[argIndex++]); argSize += 8; // always 8-byte aligned } numIntegerArgs++; break; case TR::Float: case TR::Double: if (childType == TR::Float) argRegister = pushFloatArg(child); else argRegister = pushDoubleArg(child); if (numFloatArgs < properties.getNumFloatArgRegs()) { if (!cg()->canClobberNodesRegister(child, 0)) { tempReg = cg()->allocateRegister(TR_FPR); op = (childType == TR::Float) ? TR::InstOpCode::fmovs : TR::InstOpCode::fmovd; generateTrg1Src1Instruction(cg(), op, callNode, tempReg, argRegister); argRegister = tempReg; } if ((numFloatArgs == 0 && resType.isFloatingPoint())) { TR::Register *resultReg; if (resType.getDataType() == TR::Float) resultReg = cg()->allocateSinglePrecisionRegister(); else resultReg = cg()->allocateRegister(TR_FPR); dependencies->addPreCondition(argRegister, TR::RealRegister::v0); dependencies->addPostCondition(resultReg, TR::RealRegister::v0); } else { addDependency(dependencies, argRegister, properties.getFloatArgumentRegister(numFloatArgs), TR_FPR, cg()); } } else { // numFloatArgs >= properties.getNumFloatArgRegs() if (childType == TR::Double) { op = TR::InstOpCode::vstrpostd; } else { op = TR::InstOpCode::vstrposts; } mref = getOutgoingArgumentMemRef(argMemReg, argRegister, op, pushToMemory[argIndex++]); argSize += 8; // always 8-byte aligned } numFloatArgs++; break; } // end of switch } // end of for // NULL deps for non-preserved and non-system regs while (numIntegerArgs < properties.getNumIntArgRegs()) { if (numIntegerArgs == 0 && resType.isAddress()) { dependencies->addPreCondition(cg()->allocateRegister(), properties.getIntegerArgumentRegister(0)); dependencies->addPostCondition(cg()->allocateCollectedReferenceRegister(), properties.getIntegerArgumentRegister(0)); } else { addDependency(dependencies, NULL, properties.getIntegerArgumentRegister(numIntegerArgs), TR_GPR, cg()); } numIntegerArgs++; } int32_t floatRegsUsed = (numFloatArgs > properties.getNumFloatArgRegs()) ? properties.getNumFloatArgRegs() : numFloatArgs; for (i = (TR::RealRegister::RegNum)((uint32_t)TR::RealRegister::v0 + floatRegsUsed); i <= TR::RealRegister::LastFPR; i++) { if (!properties.getPreserved((TR::RealRegister::RegNum)i)) { // NULL dependency for non-preserved regs addDependency(dependencies, NULL, (TR::RealRegister::RegNum)i, TR_FPR, cg()); } } if (numMemArgs > 0) { TR::RealRegister *sp = cg()->machine()->getRealRegister(properties.getStackPointerRegister()); generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::subimmx, callNode, argMemReg, sp, totalSize); for (argIndex = 0; argIndex < numMemArgs; argIndex++) { TR::Register *aReg = pushToMemory[argIndex].argRegister; generateMemSrc1Instruction(cg(), pushToMemory[argIndex].opCode, callNode, pushToMemory[argIndex].argMemory, aReg); cg()->stopUsingRegister(aReg); } cg()->stopUsingRegister(argMemReg); } return totalSize; }
// 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; }
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; }