void TR::ARM64SystemLinkage::createEpilogue(TR::Instruction *cursor) { TR::CodeGenerator *codeGen = cg(); const TR::ARM64LinkageProperties& properties = getProperties(); TR::Machine *machine = codeGen->machine(); TR::Node *lastNode = cursor->getNode(); TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol(); TR::RealRegister *sp = machine->getRealRegister(properties.getStackPointerRegister()); // restore callee-saved registers uint32_t offset = bodySymbol->getLocalMappingCursor(); for (int r = TR::RealRegister::x19; r <= TR::RealRegister::x28; r++) { TR::RealRegister *rr = machine->getRealRegister((TR::RealRegister::RegNum)r); if (rr->getHasBeenAssignedInMethod()) { TR::MemoryReference *stackSlot = new (trHeapMemory()) TR::MemoryReference(sp, offset, codeGen); cursor = generateTrg1MemInstruction(cg(), TR::InstOpCode::ldrimmx, lastNode, rr, stackSlot, cursor); offset += 8; } } for (int r = TR::RealRegister::v8; r <= TR::RealRegister::v15; r++) { TR::RealRegister *rr = machine->getRealRegister((TR::RealRegister::RegNum)r); if (rr->getHasBeenAssignedInMethod()) { TR::MemoryReference *stackSlot = new (trHeapMemory()) TR::MemoryReference(sp, offset, codeGen); cursor = generateTrg1MemInstruction(cg(), TR::InstOpCode::vldrimmd, lastNode, rr, stackSlot, cursor); offset += 8; } } // restore link register (x30) TR::RealRegister *lr = machine->getRealRegister(TR::RealRegister::lr); if (machine->getLinkRegisterKilled()) { TR::MemoryReference *stackSlot = new (trHeapMemory()) TR::MemoryReference(sp, 0, codeGen); cursor = generateTrg1MemInstruction(cg(), TR::InstOpCode::ldrimmx, lastNode, lr, stackSlot, cursor); } // remove space for preserved registers uint32_t frameSize = codeGen->getFrameSizeInBytes(); if (constantIsUnsignedImm12(frameSize)) { cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::addimmx, lastNode, sp, sp, frameSize, cursor); } else { TR_UNIMPLEMENTED(); } // return cursor = generateRegBranchInstruction(codeGen, TR::InstOpCode::ret, lastNode, lr, cursor); }
TR::Instruction * TR_X86SystemLinkage::savePreservedRegisters(TR::Instruction *cursor) { // For IA32, if disableShrinkWrapping, usePushForPreservedRegs will be true; otherwise false; // For X64, shrinkWraping is always on, and usePushForPreservedRegs always false; // TR_ASSERT(!getProperties().getUsesPushesForPreservedRegs(), "assertion failure"); TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol(); const int32_t localSize = getProperties().getOffsetToFirstLocal() - bodySymbol->getLocalMappingCursor(); const int32_t pointerSize = getProperties().getPointerSize(); int32_t offsetCursor = -localSize + getProperties().getOffsetToFirstLocal() - pointerSize; if (_properties.getUsesPushesForPreservedRegs()) { for (int32_t pindex = _properties.getMaxRegistersPreservedInPrologue()-1; pindex >= 0; pindex--) { TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex); TR::RealRegister *reg = machine()->getX86RealRegister(idx); if (reg->getHasBeenAssignedInMethod() && reg->getState() != TR::RealRegister::Locked) { cursor = new (trHeapMemory()) TR::X86RegInstruction(cursor, PUSHReg, reg, cg()); } } } else { TR_BitVector *p = cg()->getPreservedRegsInPrologue(); for (int32_t pindex = getProperties().getMaxRegistersPreservedInPrologue()-1; pindex >= 0; pindex--) { TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex); TR::RealRegister *reg = machine()->getX86RealRegister(getProperties().getPreservedRegister((uint32_t)pindex)); if(reg->getHasBeenAssignedInMethod() && reg->getState() != TR::RealRegister::Locked) { if (!p || p->get(idx)) { cursor = generateMemRegInstruction( cursor, movOpcodes[MemReg][fullRegisterMovType(reg)], generateX86MemoryReference(machine()->getX86RealRegister(TR::RealRegister::vfp), offsetCursor, cg()), reg, cg() ); } offsetCursor -= pointerSize; } } } return cursor; }
TR::Instruction * TR::X86SystemLinkage::savePreservedRegisters(TR::Instruction *cursor) { // For IA32 usePushForPreservedRegs will be true; // For X64, usePushForPreservedRegs always false; TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol(); const int32_t localSize = getProperties().getOffsetToFirstLocal() - bodySymbol->getLocalMappingCursor(); const int32_t pointerSize = getProperties().getPointerSize(); int32_t offsetCursor = -localSize + getProperties().getOffsetToFirstLocal() - pointerSize; if (_properties.getUsesPushesForPreservedRegs()) { for (int32_t pindex = _properties.getMaxRegistersPreservedInPrologue()-1; pindex >= 0; pindex--) { TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex); TR::RealRegister *reg = machine()->getX86RealRegister(idx); if (reg->getHasBeenAssignedInMethod() && reg->getState() != TR::RealRegister::Locked) { cursor = new (trHeapMemory()) TR::X86RegInstruction(cursor, PUSHReg, reg, cg()); } } } else { for (int32_t pindex = getProperties().getMaxRegistersPreservedInPrologue()-1; pindex >= 0; pindex--) { TR::RealRegister::RegNum idx = _properties.getPreservedRegister((uint32_t)pindex); TR::RealRegister *reg = machine()->getX86RealRegister(getProperties().getPreservedRegister((uint32_t)pindex)); if(reg->getHasBeenAssignedInMethod() && reg->getState() != TR::RealRegister::Locked) { cursor = generateMemRegInstruction( cursor, TR::Linkage::movOpcodes(MemReg, fullRegisterMovType(reg)), generateX86MemoryReference(machine()->getX86RealRegister(TR::RealRegister::vfp), offsetCursor, cg()), reg, cg() ); offsetCursor -= pointerSize; } } } return cursor; }
void TR::ARM64SystemLinkage::createPrologue(TR::Instruction *cursor, List<TR::ParameterSymbol> &parmList) { TR::CodeGenerator *codeGen = cg(); TR::Machine *machine = codeGen->machine(); TR::ResolvedMethodSymbol *bodySymbol = comp()->getJittedMethodSymbol(); const TR::ARM64LinkageProperties& properties = getProperties(); TR::RealRegister *sp = machine->getRealRegister(properties.getStackPointerRegister()); TR::Node *firstNode = comp()->getStartTree()->getNode(); // allocate stack space uint32_t frameSize = (uint32_t)codeGen->getFrameSizeInBytes(); if (constantIsUnsignedImm12(frameSize)) { cursor = generateTrg1Src1ImmInstruction(codeGen, TR::InstOpCode::subimmx, firstNode, sp, sp, frameSize, cursor); } else { TR_UNIMPLEMENTED(); } // save link register (x30) if (machine->getLinkRegisterKilled()) { TR::MemoryReference *stackSlot = new (trHeapMemory()) TR::MemoryReference(sp, 0, codeGen); cursor = generateMemSrc1Instruction(cg(), TR::InstOpCode::strimmx, firstNode, stackSlot, machine->getRealRegister(TR::RealRegister::x30), cursor); } // spill argument registers int32_t nextIntArgReg = 0; int32_t nextFltArgReg = 0; ListIterator<TR::ParameterSymbol> parameterIterator(&parmList); for (TR::ParameterSymbol *parameter = parameterIterator.getFirst(); parameter != NULL && (nextIntArgReg < getProperties().getNumIntArgRegs() || nextFltArgReg < getProperties().getNumFloatArgRegs()); parameter = parameterIterator.getNext()) { TR::MemoryReference *stackSlot = new (trHeapMemory()) TR::MemoryReference(sp, parameter->getParameterOffset(), codeGen); TR::InstOpCode::Mnemonic op; switch (parameter->getDataType()) { case TR::Int8: case TR::Int16: case TR::Int32: case TR::Int64: case TR::Address: if (nextIntArgReg < getProperties().getNumIntArgRegs()) { op = (parameter->getSize() == 8) ? TR::InstOpCode::strimmx : TR::InstOpCode::strimmw; cursor = generateMemSrc1Instruction(cg(), op, firstNode, stackSlot, machine->getRealRegister((TR::RealRegister::RegNum)(TR::RealRegister::x0 + nextIntArgReg)), cursor); nextIntArgReg++; } else { nextIntArgReg = getProperties().getNumIntArgRegs() + 1; } break; case TR::Float: case TR::Double: if (nextFltArgReg < getProperties().getNumFloatArgRegs()) { op = (parameter->getSize() == 8) ? TR::InstOpCode::vstrimmd : TR::InstOpCode::vstrimms; cursor = generateMemSrc1Instruction(cg(), op, firstNode, stackSlot, machine->getRealRegister((TR::RealRegister::RegNum)(TR::RealRegister::v0 + nextFltArgReg)), cursor); nextFltArgReg++; } 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 callee-saved registers uint32_t offset = bodySymbol->getLocalMappingCursor(); for (int r = TR::RealRegister::x19; r <= TR::RealRegister::x28; r++) { TR::RealRegister *rr = machine->getRealRegister((TR::RealRegister::RegNum)r); if (rr->getHasBeenAssignedInMethod()) { TR::MemoryReference *stackSlot = new (trHeapMemory()) TR::MemoryReference(sp, offset, codeGen); cursor = generateMemSrc1Instruction(cg(), TR::InstOpCode::strimmx, firstNode, stackSlot, rr, cursor); offset += 8; } } for (int r = TR::RealRegister::v8; r <= TR::RealRegister::v15; r++) { TR::RealRegister *rr = machine->getRealRegister((TR::RealRegister::RegNum)r); if (rr->getHasBeenAssignedInMethod()) { TR::MemoryReference *stackSlot = new (trHeapMemory()) TR::MemoryReference(sp, offset, codeGen); cursor = generateMemSrc1Instruction(cg(), TR::InstOpCode::vstrimmd, firstNode, stackSlot, rr, cursor); offset += 8; } } }
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."); } } }