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."); } } }