void OMR::CodeGenerator::prepareNodeForInstructionSelection(TR::Node *node) { if (node->getVisitCount() == self()->comp()->getVisitCount()) { if (node->getOpCode().hasSymbolReference() && node->getSymbolReference()->isTempVariableSizeSymRef()) { // bcd loads and loadaddr's do not get put into registers so must increment the symbol reference count for commoned nodes too TR::AutomaticSymbol *local = node->getSymbol()->getAutoSymbol(); TR_ASSERT(local,"a tempMemSlot should have an auto symbol\n"); local->incReferenceCount(); } return; } if (node->getOpCode().hasSymbolReference()) { TR::AutomaticSymbol *local = node->getSymbol()->getAutoSymbol(); if (local) { local->incReferenceCount(); } } node->setVisitCount(self()->comp()->getVisitCount()); node->setRegister(NULL); node->setHasBeenVisitedForHints(false); // clear this flag for addStorageReferenceHints pass for (int32_t childCount = node->getNumChildren() - 1; childCount >= 0; childCount--) { self()->prepareNodeForInstructionSelection(node->getChild(childCount)); } }
void TR::ARM64SystemLinkage::mapStack(TR::ResolvedMethodSymbol *method) { TR::Machine *machine = cg()->machine(); uint32_t stackIndex = 0; ListIterator<TR::AutomaticSymbol> automaticIterator(&method->getAutomaticList()); TR::AutomaticSymbol *localCursor = automaticIterator.getFirst(); stackIndex = 8; // [sp+0] is for link register // map non-long/double automatics while (localCursor != NULL) { if (localCursor->getGCMapIndex() < 0 && localCursor->getDataType() != TR::Int64 && localCursor->getDataType() != TR::Double) { localCursor->setOffset(stackIndex); stackIndex += (localCursor->getSize() + 3) & (~3); } localCursor = automaticIterator.getNext(); } stackIndex += (stackIndex & 0x4) ? 4 : 0; // align to 8 bytes automaticIterator.reset(); localCursor = automaticIterator.getFirst(); // map long/double automatics while (localCursor != NULL) { if (localCursor->getDataType() == TR::Int64 || localCursor->getDataType() == TR::Double) { localCursor->setOffset(stackIndex); stackIndex += (localCursor->getSize() + 7) & (~7); } localCursor = automaticIterator.getNext(); } method->setLocalMappingCursor(stackIndex); // allocate space for preserved registers (x19-x28, v8-v15) for (int r = TR::RealRegister::x19; r <= TR::RealRegister::x28; r++) { TR::RealRegister *rr = machine->getRealRegister((TR::RealRegister::RegNum)r); if (rr->getHasBeenAssignedInMethod()) { stackIndex += 8; } } for (int r = TR::RealRegister::v8; r <= TR::RealRegister::v15; r++) { TR::RealRegister *rr = machine->getRealRegister((TR::RealRegister::RegNum)r); if (rr->getHasBeenAssignedInMethod()) { stackIndex += 8; } } /* * Because the rest of the code generator currently expects **all** arguments * to be passed on the stack, arguments passed in registers must be spilled * in the callee frame. To map the arguments correctly, we use two loops. The * first maps the arguments that will come in registers onto the callee stack. * At the end of this loop, the `stackIndex` is the the size of the frame. * The second loop then maps the remaining arguments onto the caller frame. */ int32_t nextIntArgReg = 0; int32_t nextFltArgReg = 0; ListIterator<TR::ParameterSymbol> parameterIterator(&method->getParameterList()); for (TR::ParameterSymbol *parameter = parameterIterator.getFirst(); parameter != NULL && (nextIntArgReg < getProperties().getNumIntArgRegs() || nextFltArgReg < getProperties().getNumFloatArgRegs()); parameter = parameterIterator.getNext()) { switch (parameter->getDataType()) { case TR::Int8: case TR::Int16: case TR::Int32: case TR::Int64: case TR::Address: if (nextIntArgReg < getProperties().getNumIntArgRegs()) { nextIntArgReg++; mapSingleParameter(parameter, stackIndex, true); } else { nextIntArgReg = getProperties().getNumIntArgRegs() + 1; } break; case TR::Float: case TR::Double: if (nextFltArgReg < getProperties().getNumFloatArgRegs()) { nextFltArgReg++; mapSingleParameter(parameter, stackIndex, true); } else { nextFltArgReg = getProperties().getNumFloatArgRegs() + 1; } break; case TR::Aggregate: TR_ASSERT(false, "Function parameters of aggregate types are not currently supported on AArch64."); break; default: TR_ASSERT(false, "Unknown parameter type."); } } // save the stack frame size, aligned to 16 bytes stackIndex = (stackIndex + 15) & (~15); cg()->setFrameSizeInBytes(stackIndex); nextIntArgReg = 0; nextFltArgReg = 0; parameterIterator.reset(); for (TR::ParameterSymbol *parameter = parameterIterator.getFirst(); parameter != NULL && (nextIntArgReg < getProperties().getNumIntArgRegs() || nextFltArgReg < getProperties().getNumFloatArgRegs()); parameter = parameterIterator.getNext()) { switch (parameter->getDataType()) { case TR::Int8: case TR::Int16: case TR::Int32: case TR::Int64: case TR::Address: if (nextIntArgReg < getProperties().getNumIntArgRegs()) { nextIntArgReg++; } else { mapSingleParameter(parameter, stackIndex, false); } break; case TR::Float: case TR::Double: if (nextFltArgReg < getProperties().getNumFloatArgRegs()) { nextFltArgReg++; } else { mapSingleParameter(parameter, stackIndex, false); } break; case TR::Aggregate: TR_ASSERT(false, "Function parameters of aggregate types are not currently supported on AArch64."); break; default: TR_ASSERT(false, "Unknown parameter type."); } } }
/** * @brief Maps symbols in the IL to locations on the stack * @param method is the method for which symbols are being stack mapped * * In general, the shape of a stack frame is as follows: * * +-----------------------------+ * | caller frame | * +-----------------------------+ * | stack arguments | * +=============================+ <-+ (start of callee frame) * | saved registers | | * +-----------------------------+ | frame size * | locals | | * +-----------------------------+ <-+- $sp * * A symbol is mapped onto the stack by assigning to it an offset from the stack * pointer. All symbols representing stack allocated values must be mapped, * including automatics (locals) on the callee frame and stack allocated * arguments on the caller frame * * The algorithm used to map symbols iterates over each symbol in ascending * address order. Using the frame shape depicted above as a general example: * locals are mapped first, registers second. The algorithm is: * * 1. Set stackIndex to 0 * 2. For each symbol that must be mapped onto the **callee** stack frame, * starting at the lowest address: * a. set stackIndex as the symbol offset * b. increment stackIndex by the size of the symbol's type * plus alignment requirements * 3. Increment stackIndex by the necessary amount to account for the stack * space required for saved registers * 4. Save stackIndex as the size of the callee stack frame * 5. For each symbol that must be mapped onto the **caller** stack frame, * starting at the lowest address: * a. set the symbol offset as the current stack index * b. increment the stack index by the size of the symbol's type, * plus alignment requirements */ void TR::ARMSystemLinkage::mapStack(TR::ResolvedMethodSymbol *method) { uint32_t stackIndex = 0; ListIterator<TR::AutomaticSymbol> automaticIterator(&method->getAutomaticList()); TR::AutomaticSymbol *localCursor = automaticIterator.getFirst(); // map non-double automatics while (localCursor != NULL) { if (localCursor->getGCMapIndex() < 0 && localCursor->getDataType() != TR::Double) { localCursor->setOffset(stackIndex); stackIndex += (localCursor->getSize()+3)&(~3); } localCursor = automaticIterator.getNext(); } stackIndex += (stackIndex & 0x4) ? 4 : 0; // align to 8 bytes automaticIterator.reset(); localCursor = automaticIterator.getFirst(); // map double automatics while (localCursor != NULL) { if (localCursor->getDataType() == TR::Double) { localCursor->setOffset(stackIndex); stackIndex += (localCursor->getSize()+7)&(~7); } localCursor = automaticIterator.getNext(); } method->setLocalMappingCursor(stackIndex); // allocate space for preserved registers and link register (9 registers total) stackIndex += 9*4; /* * Because the rest of the code generator currently expects **all** arguments * to be passed on the stack, arguments passed in registers must be spilled * in the callee frame. To map the arguments correctly, we use two loops. The * first maps the arguments that will come in registers onto the callee stack. * At the end of this loop, the `stackIndex` is the the size of the frame. * The second loop then maps the remaining arguments onto the caller frame. */ auto nextIntArgReg = 0; auto nextFltArgReg = 0; ListIterator<TR::ParameterSymbol> parameterIterator(&method->getParameterList()); for (TR::ParameterSymbol *parameter = parameterIterator.getFirst(); parameter!=NULL && (nextIntArgReg < getProperties().getNumIntArgRegs() || nextFltArgReg < getProperties().getNumFloatArgRegs()); parameter=parameterIterator.getNext()) { switch (parameter->getDataType()) { case TR::Int8: case TR::Int16: case TR::Int32: case TR::Address: if (nextIntArgReg < getProperties().getNumIntArgRegs()) { nextIntArgReg++; mapSingleParameter(parameter, stackIndex); } else { nextIntArgReg = getProperties().getNumIntArgRegs() + 1; } break; case TR::Int64: nextIntArgReg += nextIntArgReg & 0x1; // round to next even number if (nextIntArgReg + 1 < getProperties().getNumIntArgRegs()) { nextIntArgReg += 2; mapSingleParameter(parameter, stackIndex); } else { nextIntArgReg = getProperties().getNumIntArgRegs() + 1; } break; case TR::Float: comp()->failCompilation<UnsupportedParameterType>("Compiling methods with a single precision floating point parameter is not supported"); break; case TR::Double: if (nextFltArgReg < getProperties().getNumFloatArgRegs()) { nextFltArgReg += 1; mapSingleParameter(parameter, stackIndex); } else { nextFltArgReg = getProperties().getNumFloatArgRegs() + 1; } break; case TR::Aggregate: TR_ASSERT(false, "Function parameters of aggregate types are not currently supported on ARM."); } } // save the stack frame size, aligned to 8 bytes stackIndex = (stackIndex + 7)&(~7); cg()->setFrameSizeInBytes(stackIndex); nextIntArgReg = 0; nextFltArgReg = 0; parameterIterator.reset(); for (TR::ParameterSymbol *parameter = parameterIterator.getFirst(); parameter!=NULL && (nextIntArgReg < getProperties().getNumIntArgRegs() || nextFltArgReg < getProperties().getNumFloatArgRegs()); parameter=parameterIterator.getNext()) { switch (parameter->getDataType()) { case TR::Int8: case TR::Int16: case TR::Int32: case TR::Address: if (nextIntArgReg < getProperties().getNumIntArgRegs()) { nextIntArgReg++; } else { mapSingleParameter(parameter, stackIndex); } break; case TR::Int64: nextIntArgReg += stackIndex & 0x1; // round to next even number if (nextIntArgReg + 1 < getProperties().getNumIntArgRegs()) { nextIntArgReg += 2; } else { mapSingleParameter(parameter, stackIndex); } break; case TR::Float: comp()->failCompilation<UnsupportedParameterType>("Compiling methods with a single precision floating point parameter is not supported"); break; case TR::Double: if (nextFltArgReg < getProperties().getNumFloatArgRegs()) { nextFltArgReg += 1; } else { mapSingleParameter(parameter, stackIndex); } break; case TR::Aggregate: TR_ASSERT(false, "Function parameters of aggregate types are not currently supported on ARM."); } } }