1251607Sdim//===-- SystemZRegisterInfo.cpp - SystemZ register information ------------===//
2251607Sdim//
3251607Sdim//                     The LLVM Compiler Infrastructure
4251607Sdim//
5251607Sdim// This file is distributed under the University of Illinois Open Source
6251607Sdim// License. See LICENSE.TXT for details.
7251607Sdim//
8251607Sdim//===----------------------------------------------------------------------===//
9251607Sdim
10251607Sdim#include "SystemZRegisterInfo.h"
11251607Sdim#include "SystemZTargetMachine.h"
12251607Sdim#include "llvm/CodeGen/MachineInstrBuilder.h"
13251607Sdim#include "llvm/CodeGen/MachineRegisterInfo.h"
14251607Sdim
15251607Sdim#define GET_REGINFO_TARGET_DESC
16251607Sdim#include "SystemZGenRegisterInfo.inc"
17251607Sdim
18251607Sdimusing namespace llvm;
19251607Sdim
20251607SdimSystemZRegisterInfo::SystemZRegisterInfo(SystemZTargetMachine &tm,
21251607Sdim                                         const SystemZInstrInfo &tii)
22251607Sdim  : SystemZGenRegisterInfo(SystemZ::R14D), TM(tm), TII(tii) {}
23251607Sdim
24251607Sdimconst uint16_t*
25251607SdimSystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
26251607Sdim  static const uint16_t CalleeSavedRegs[] = {
27251607Sdim    SystemZ::R6D,  SystemZ::R7D,  SystemZ::R8D,  SystemZ::R9D,
28251607Sdim    SystemZ::R10D, SystemZ::R11D, SystemZ::R12D, SystemZ::R13D,
29251607Sdim    SystemZ::R14D, SystemZ::R15D,
30251607Sdim    SystemZ::F8D,  SystemZ::F9D,  SystemZ::F10D, SystemZ::F11D,
31251607Sdim    SystemZ::F12D, SystemZ::F13D, SystemZ::F14D, SystemZ::F15D,
32251607Sdim    0
33251607Sdim  };
34251607Sdim
35251607Sdim  return CalleeSavedRegs;
36251607Sdim}
37251607Sdim
38251607SdimBitVector
39251607SdimSystemZRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
40251607Sdim  BitVector Reserved(getNumRegs());
41251607Sdim  const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
42251607Sdim
43251607Sdim  if (TFI->hasFP(MF)) {
44251607Sdim    // R11D is the frame pointer.  Reserve all aliases.
45251607Sdim    Reserved.set(SystemZ::R11D);
46251607Sdim    Reserved.set(SystemZ::R11W);
47251607Sdim    Reserved.set(SystemZ::R10Q);
48251607Sdim  }
49251607Sdim
50251607Sdim  // R15D is the stack pointer.  Reserve all aliases.
51251607Sdim  Reserved.set(SystemZ::R15D);
52251607Sdim  Reserved.set(SystemZ::R15W);
53251607Sdim  Reserved.set(SystemZ::R14Q);
54251607Sdim  return Reserved;
55251607Sdim}
56251607Sdim
57251607Sdimbool
58251607SdimSystemZRegisterInfo::saveScavengerRegister(MachineBasicBlock &MBB,
59251607Sdim					   MachineBasicBlock::iterator SaveMBBI,
60251607Sdim					   MachineBasicBlock::iterator &UseMBBI,
61251607Sdim					   const TargetRegisterClass *RC,
62251607Sdim					   unsigned Reg) const {
63251607Sdim  MachineFunction &MF = *MBB.getParent();
64251607Sdim  const SystemZFrameLowering *TFI =
65251607Sdim    static_cast<const SystemZFrameLowering *>(TM.getFrameLowering());
66251607Sdim  unsigned Base = getFrameRegister(MF);
67251607Sdim  uint64_t Offset = TFI->getEmergencySpillSlotOffset(MF);
68251607Sdim  DebugLoc DL;
69251607Sdim
70251607Sdim  unsigned LoadOpcode, StoreOpcode;
71251607Sdim  TII.getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode);
72251607Sdim
73251607Sdim  // The offset must always be in range of a 12-bit unsigned displacement.
74251607Sdim  BuildMI(MBB, SaveMBBI, DL, TII.get(StoreOpcode))
75251607Sdim    .addReg(Reg, RegState::Kill).addReg(Base).addImm(Offset).addReg(0);
76251607Sdim  BuildMI(MBB, UseMBBI, DL, TII.get(LoadOpcode), Reg)
77251607Sdim    .addReg(Base).addImm(Offset).addReg(0);
78251607Sdim  return true;
79251607Sdim}
80251607Sdim
81251607Sdimvoid
82251607SdimSystemZRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
83251607Sdim                                         int SPAdj, unsigned FIOperandNum,
84251607Sdim                                         RegScavenger *RS) const {
85251607Sdim  assert(SPAdj == 0 && "Outgoing arguments should be part of the frame");
86251607Sdim
87251607Sdim  MachineBasicBlock &MBB = *MI->getParent();
88251607Sdim  MachineFunction &MF = *MBB.getParent();
89251607Sdim  const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
90251607Sdim  DebugLoc DL = MI->getDebugLoc();
91251607Sdim
92251607Sdim  // Decompose the frame index into a base and offset.
93251607Sdim  int FrameIndex = MI->getOperand(FIOperandNum).getIndex();
94251607Sdim  unsigned BasePtr = getFrameRegister(MF);
95251607Sdim  int64_t Offset = (TFI->getFrameIndexOffset(MF, FrameIndex) +
96251607Sdim                    MI->getOperand(FIOperandNum + 1).getImm());
97251607Sdim
98251607Sdim  // Special handling of dbg_value instructions.
99251607Sdim  if (MI->isDebugValue()) {
100251607Sdim    MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, /*isDef*/ false);
101251607Sdim    MI->getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
102251607Sdim    return;
103251607Sdim  }
104251607Sdim
105251607Sdim  // See if the offset is in range, or if an equivalent instruction that
106251607Sdim  // accepts the offset exists.
107251607Sdim  unsigned Opcode = MI->getOpcode();
108251607Sdim  unsigned OpcodeForOffset = TII.getOpcodeForOffset(Opcode, Offset);
109251607Sdim  if (OpcodeForOffset)
110251607Sdim    MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, false);
111251607Sdim  else {
112251607Sdim    // Create an anchor point that is in range.  Start at 0xffff so that
113251607Sdim    // can use LLILH to load the immediate.
114251607Sdim    int64_t OldOffset = Offset;
115251607Sdim    int64_t Mask = 0xffff;
116251607Sdim    do {
117251607Sdim      Offset = OldOffset & Mask;
118251607Sdim      OpcodeForOffset = TII.getOpcodeForOffset(Opcode, Offset);
119251607Sdim      Mask >>= 1;
120251607Sdim      assert(Mask && "One offset must be OK");
121251607Sdim    } while (!OpcodeForOffset);
122251607Sdim
123251607Sdim    unsigned ScratchReg =
124251607Sdim      MF.getRegInfo().createVirtualRegister(&SystemZ::ADDR64BitRegClass);
125251607Sdim    int64_t HighOffset = OldOffset - Offset;
126251607Sdim
127251607Sdim    if (MI->getDesc().TSFlags & SystemZII::HasIndex
128251607Sdim        && MI->getOperand(FIOperandNum + 2).getReg() == 0) {
129251607Sdim      // Load the offset into the scratch register and use it as an index.
130251607Sdim      // The scratch register then dies here.
131251607Sdim      TII.loadImmediate(MBB, MI, ScratchReg, HighOffset);
132251607Sdim      MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, false);
133251607Sdim      MI->getOperand(FIOperandNum + 2).ChangeToRegister(ScratchReg,
134251607Sdim                                                        false, false, true);
135251607Sdim    } else {
136251607Sdim      // Load the anchor address into a scratch register.
137251607Sdim      unsigned LAOpcode = TII.getOpcodeForOffset(SystemZ::LA, HighOffset);
138251607Sdim      if (LAOpcode)
139251607Sdim        BuildMI(MBB, MI, DL, TII.get(LAOpcode),ScratchReg)
140251607Sdim          .addReg(BasePtr).addImm(HighOffset).addReg(0);
141251607Sdim      else {
142251607Sdim        // Load the high offset into the scratch register and use it as
143251607Sdim        // an index.
144251607Sdim        TII.loadImmediate(MBB, MI, ScratchReg, HighOffset);
145251607Sdim        BuildMI(MBB, MI, DL, TII.get(SystemZ::AGR),ScratchReg)
146251607Sdim          .addReg(ScratchReg, RegState::Kill).addReg(BasePtr);
147251607Sdim      }
148251607Sdim
149251607Sdim      // Use the scratch register as the base.  It then dies here.
150251607Sdim      MI->getOperand(FIOperandNum).ChangeToRegister(ScratchReg,
151251607Sdim                                                    false, false, true);
152251607Sdim    }
153251607Sdim  }
154251607Sdim  MI->setDesc(TII.get(OpcodeForOffset));
155251607Sdim  MI->getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
156251607Sdim}
157251607Sdim
158251607Sdimunsigned
159251607SdimSystemZRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
160251607Sdim  const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
161251607Sdim  return TFI->hasFP(MF) ? SystemZ::R11D : SystemZ::R15D;
162251607Sdim}
163