mirror of
https://github.com/RPCS3/llvm.git
synced 2025-05-13 08:56:04 +00:00

Note: I do not implement a base pointer, so it's still impossible to have dynamic realignment AND dynamic alloca in the same function. This also moves the code for determining the frame index reference into getFrameIndexReference, where it belongs, instead of inline in eliminateFrameIndex. [Begin long-winded screed] Now, stack realignment for Sparc is actually a silly thing to support, because the Sparc ABI has no need for it -- unlike the situation on x86, the stack is ALWAYS aligned to the required alignment for the CPU instructions: 8 bytes on sparcv8, and 16 bytes on sparcv9. However, LLVM unfortunately implements user-specified overalignment using stack realignment support, so for now, I'm going to go along with that tradition. GCC instead treats objects which have alignment specification greater than the maximum CPU-required alignment for the target as a separate block of stack memory, with their own virtual base pointer (which gets aligned). Doing it that way avoids needing to implement per-target support for stack realignment, except for the targets which *actually* have an ABI-specified stack alignment which is too small for the CPU's requirements. Further unfortunately in LLVM, the default canRealignStack for all targets effectively returns true, despite that implementing that is something a target needs to do specifically. So, the previous behavior on Sparc was to silently ignore the user's specified stack alignment. Ugh. Yet MORE unfortunate, if a target actually does return false from canRealignStack, that also causes the user-specified alignment to be *silently ignored*, rather than emitting an error. (I started looking into fixing that last, but it broke a bunch of tests, because LLVM actually *depends* on having it silently ignored: some architectures (e.g. non-linux i386) have smaller stack alignment than spilled-register alignment. But, the fact that a register needs spilling is not known until within the register allocator. And by that point, the decision to not reserve the frame pointer has been frozen in place. And without a frame pointer, stack realignment is not possible. So, canRealignStack() returns false, and needsStackRealignment() then returns false, assuming everyone can just go on their merry way assuming the alignment requirements were probably just suggestions after-all. Sigh...) Differential Revision: http://reviews.llvm.org/D12208 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@245668 91177308-0d34-0410-b5e6-96231b3b80d8
242 lines
8.2 KiB
C++
242 lines
8.2 KiB
C++
//===-- SparcRegisterInfo.cpp - SPARC Register Information ----------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file contains the SPARC implementation of the TargetRegisterInfo class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SparcRegisterInfo.h"
|
|
#include "Sparc.h"
|
|
#include "SparcMachineFunctionInfo.h"
|
|
#include "SparcSubtarget.h"
|
|
#include "llvm/ADT/BitVector.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/IR/Type.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define GET_REGINFO_TARGET_DESC
|
|
#include "SparcGenRegisterInfo.inc"
|
|
|
|
static cl::opt<bool>
|
|
ReserveAppRegisters("sparc-reserve-app-registers", cl::Hidden, cl::init(false),
|
|
cl::desc("Reserve application registers (%g2-%g4)"));
|
|
|
|
SparcRegisterInfo::SparcRegisterInfo() : SparcGenRegisterInfo(SP::O7) {}
|
|
|
|
const MCPhysReg*
|
|
SparcRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
|
|
return CSR_SaveList;
|
|
}
|
|
|
|
const uint32_t *
|
|
SparcRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
|
|
CallingConv::ID CC) const {
|
|
return CSR_RegMask;
|
|
}
|
|
|
|
const uint32_t*
|
|
SparcRegisterInfo::getRTCallPreservedMask(CallingConv::ID CC) const {
|
|
return RTCSR_RegMask;
|
|
}
|
|
|
|
BitVector SparcRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
|
|
BitVector Reserved(getNumRegs());
|
|
const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
|
|
// FIXME: G1 reserved for now for large imm generation by frame code.
|
|
Reserved.set(SP::G1);
|
|
|
|
// G1-G4 can be used in applications.
|
|
if (ReserveAppRegisters) {
|
|
Reserved.set(SP::G2);
|
|
Reserved.set(SP::G3);
|
|
Reserved.set(SP::G4);
|
|
}
|
|
// G5 is not reserved in 64 bit mode.
|
|
if (!Subtarget.is64Bit())
|
|
Reserved.set(SP::G5);
|
|
|
|
Reserved.set(SP::O6);
|
|
Reserved.set(SP::I6);
|
|
Reserved.set(SP::I7);
|
|
Reserved.set(SP::G0);
|
|
Reserved.set(SP::G6);
|
|
Reserved.set(SP::G7);
|
|
|
|
// Also reserve the register pair aliases covering the above
|
|
// registers, with the same conditions.
|
|
Reserved.set(SP::G0_G1);
|
|
if (ReserveAppRegisters)
|
|
Reserved.set(SP::G2_G3);
|
|
if (ReserveAppRegisters || !Subtarget.is64Bit())
|
|
Reserved.set(SP::G4_G5);
|
|
|
|
Reserved.set(SP::O6_O7);
|
|
Reserved.set(SP::I6_I7);
|
|
Reserved.set(SP::G6_G7);
|
|
|
|
// Unaliased double registers are not available in non-V9 targets.
|
|
if (!Subtarget.isV9()) {
|
|
for (unsigned n = 0; n != 16; ++n) {
|
|
for (MCRegAliasIterator AI(SP::D16 + n, this, true); AI.isValid(); ++AI)
|
|
Reserved.set(*AI);
|
|
}
|
|
}
|
|
|
|
return Reserved;
|
|
}
|
|
|
|
const TargetRegisterClass*
|
|
SparcRegisterInfo::getPointerRegClass(const MachineFunction &MF,
|
|
unsigned Kind) const {
|
|
const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
|
|
return Subtarget.is64Bit() ? &SP::I64RegsRegClass : &SP::IntRegsRegClass;
|
|
}
|
|
|
|
static void replaceFI(MachineFunction &MF,
|
|
MachineBasicBlock::iterator II,
|
|
MachineInstr &MI,
|
|
DebugLoc dl,
|
|
unsigned FIOperandNum, int Offset,
|
|
unsigned FramePtr)
|
|
{
|
|
// Replace frame index with a frame pointer reference.
|
|
if (Offset >= -4096 && Offset <= 4095) {
|
|
// If the offset is small enough to fit in the immediate field, directly
|
|
// encode it.
|
|
MI.getOperand(FIOperandNum).ChangeToRegister(FramePtr, false);
|
|
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
|
|
return;
|
|
}
|
|
|
|
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
|
|
|
|
// FIXME: it would be better to scavenge a register here instead of
|
|
// reserving G1 all of the time.
|
|
if (Offset >= 0) {
|
|
// Emit nonnegaive immediates with sethi + or.
|
|
// sethi %hi(Offset), %g1
|
|
// add %g1, %fp, %g1
|
|
// Insert G1+%lo(offset) into the user.
|
|
BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1)
|
|
.addImm(HI22(Offset));
|
|
|
|
|
|
// Emit G1 = G1 + I6
|
|
BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1)
|
|
.addReg(FramePtr);
|
|
// Insert: G1+%lo(offset) into the user.
|
|
MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false);
|
|
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(LO10(Offset));
|
|
return;
|
|
}
|
|
|
|
// Emit Negative numbers with sethi + xor
|
|
// sethi %hix(Offset), %g1
|
|
// xor %g1, %lox(offset), %g1
|
|
// add %g1, %fp, %g1
|
|
// Insert: G1 + 0 into the user.
|
|
BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1)
|
|
.addImm(HIX22(Offset));
|
|
BuildMI(*MI.getParent(), II, dl, TII.get(SP::XORri), SP::G1)
|
|
.addReg(SP::G1).addImm(LOX10(Offset));
|
|
|
|
BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1)
|
|
.addReg(FramePtr);
|
|
// Insert: G1+%lo(offset) into the user.
|
|
MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false);
|
|
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(0);
|
|
}
|
|
|
|
|
|
void
|
|
SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
|
int SPAdj, unsigned FIOperandNum,
|
|
RegScavenger *RS) const {
|
|
assert(SPAdj == 0 && "Unexpected");
|
|
|
|
MachineInstr &MI = *II;
|
|
DebugLoc dl = MI.getDebugLoc();
|
|
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
|
|
MachineFunction &MF = *MI.getParent()->getParent();
|
|
const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
|
|
const SparcFrameLowering *TFI = getFrameLowering(MF);
|
|
|
|
unsigned FrameReg;
|
|
int Offset;
|
|
Offset = TFI->getFrameIndexReference(MF, FrameIndex, FrameReg);
|
|
|
|
Offset += MI.getOperand(FIOperandNum + 1).getImm();
|
|
|
|
if (!Subtarget.isV9() || !Subtarget.hasHardQuad()) {
|
|
if (MI.getOpcode() == SP::STQFri) {
|
|
const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
|
|
unsigned SrcReg = MI.getOperand(2).getReg();
|
|
unsigned SrcEvenReg = getSubReg(SrcReg, SP::sub_even64);
|
|
unsigned SrcOddReg = getSubReg(SrcReg, SP::sub_odd64);
|
|
MachineInstr *StMI =
|
|
BuildMI(*MI.getParent(), II, dl, TII.get(SP::STDFri))
|
|
.addReg(FrameReg).addImm(0).addReg(SrcEvenReg);
|
|
replaceFI(MF, II, *StMI, dl, 0, Offset, FrameReg);
|
|
MI.setDesc(TII.get(SP::STDFri));
|
|
MI.getOperand(2).setReg(SrcOddReg);
|
|
Offset += 8;
|
|
} else if (MI.getOpcode() == SP::LDQFri) {
|
|
const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
|
|
unsigned DestReg = MI.getOperand(0).getReg();
|
|
unsigned DestEvenReg = getSubReg(DestReg, SP::sub_even64);
|
|
unsigned DestOddReg = getSubReg(DestReg, SP::sub_odd64);
|
|
MachineInstr *StMI =
|
|
BuildMI(*MI.getParent(), II, dl, TII.get(SP::LDDFri), DestEvenReg)
|
|
.addReg(FrameReg).addImm(0);
|
|
replaceFI(MF, II, *StMI, dl, 1, Offset, FrameReg);
|
|
|
|
MI.setDesc(TII.get(SP::LDDFri));
|
|
MI.getOperand(0).setReg(DestOddReg);
|
|
Offset += 8;
|
|
}
|
|
}
|
|
|
|
replaceFI(MF, II, MI, dl, FIOperandNum, Offset, FrameReg);
|
|
|
|
}
|
|
|
|
unsigned SparcRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
|
|
return SP::I6;
|
|
}
|
|
|
|
// Sparc has no architectural need for stack realignment support,
|
|
// except that LLVM unfortunately currently implements overaligned
|
|
// stack objects by depending upon stack realignment support.
|
|
// If that ever changes, this can probably be deleted.
|
|
bool SparcRegisterInfo::canRealignStack(const MachineFunction &MF) const {
|
|
if (!TargetRegisterInfo::canRealignStack(MF))
|
|
return false;
|
|
|
|
// Sparc always has a fixed frame pointer register, so don't need to
|
|
// worry about needing to reserve it. [even if we don't have a frame
|
|
// pointer for our frame, it still cannot be used for other things,
|
|
// or register window traps will be SADNESS.]
|
|
|
|
// If there's a reserved call frame, we can use SP to access locals.
|
|
if (getFrameLowering(MF)->hasReservedCallFrame(MF))
|
|
return true;
|
|
|
|
// Otherwise, we'd need a base pointer, but those aren't implemented
|
|
// for SPARC at the moment.
|
|
|
|
return false;
|
|
}
|