summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/R600/SIMachineFunctionInfo.cpp
blob: 086f090870340311336933fe96b086be09e55b10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//===-- SIMachineFunctionInfo.cpp - SI Machine Function Info -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
/// \file
//===----------------------------------------------------------------------===//


#include "SIMachineFunctionInfo.h"
#include "SIInstrInfo.h"
#include "SIRegisterInfo.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"

#define MAX_LANES 64

using namespace llvm;


// Pin the vtable to this file.
void SIMachineFunctionInfo::anchor() {}

SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF)
  : AMDGPUMachineFunction(MF),
    PSInputAddr(0),
    SpillTracker(),
    NumUserSGPRs(0) { }

static unsigned createLaneVGPR(MachineRegisterInfo &MRI, MachineFunction *MF) {
  unsigned VGPR = MRI.createVirtualRegister(&AMDGPU::VReg_32RegClass);

  // We need to add this register as live out for the function, in order to
  // have the live range calculated directly.
  //
  // When register spilling begins, we have already calculated the live
  // live intervals for all the registers.  Since we are spilling SGPRs to
  // VGPRs, we need to update the Lane VGPR's live interval every time we
  // spill or restore a register.
  //
  // Unfortunately, there is no good way to update the live interval as
  // the TargetInstrInfo callbacks for spilling and restoring don't give
  // us access to the live interval information.
  //
  // We are lucky, though, because the InlineSpiller calls
  // LiveRangeEdit::calculateRegClassAndHint() which iterates through
  // all the new register that have been created when restoring a register
  // and calls LiveIntervals::getInterval(), which creates and computes
  // the live interval for the newly created register.  However, once this
  // live intervals is created, it doesn't change and since we usually reuse
  // the Lane VGPR multiple times, this means any uses after the first aren't
  // added to the live interval.
  //
  // To work around this, we add Lane VGPRs to the functions live out list,
  // so that we can guarantee its live range will cover all of its uses.

  for (MachineBasicBlock &MBB : *MF) {
    if (MBB.back().getOpcode() == AMDGPU::S_ENDPGM) {
      MBB.back().addOperand(*MF, MachineOperand::CreateReg(VGPR, false, true));
      return VGPR;
    }
  }

  LLVMContext &Ctx = MF->getFunction()->getContext();
  Ctx.emitError("Could not find S_ENDPGM instruction.");

  return VGPR;
}

unsigned SIMachineFunctionInfo::RegSpillTracker::reserveLanes(
    MachineRegisterInfo &MRI, MachineFunction *MF, unsigned NumRegs) {
  unsigned StartLane = CurrentLane;
  CurrentLane += NumRegs;
  if (!LaneVGPR) {
    LaneVGPR = createLaneVGPR(MRI, MF);
  } else {
    if (CurrentLane >= MAX_LANES) {
      StartLane = CurrentLane = 0;
      LaneVGPR = createLaneVGPR(MRI, MF);
    }
  }
  return StartLane;
}

void SIMachineFunctionInfo::RegSpillTracker::addSpilledReg(unsigned FrameIndex,
                                                           unsigned Reg,
                                                           int Lane) {
  SpilledRegisters[FrameIndex] = SpilledReg(Reg, Lane);
}
/// \brief Returns a register that is not used at any point in the function.
///        If all registers are used, then this function will return
//         AMDGPU::NoRegister.
static unsigned findUnusedVGPR(const MachineRegisterInfo &MRI) {

  const TargetRegisterClass *RC = &AMDGPU::VGPR_32RegClass;

  for (TargetRegisterClass::iterator I = RC->begin(), E = RC->end();
       I != E; ++I) {
    if (!MRI.isPhysRegUsed(*I))
      return *I;
  }
  return AMDGPU::NoRegister;
}

SIMachineFunctionInfo::SpilledReg SIMachineFunctionInfo::getSpilledReg(
                                                       MachineFunction *MF,
                                                       unsigned FrameIndex,
                                                       unsigned SubIdx) {
  const MachineFrameInfo *FrameInfo = MF->getFrameInfo();
  MachineRegisterInfo &MRI = MF->getRegInfo();
  int64_t Offset = FrameInfo->getObjectOffset(FrameIndex);
  Offset += SubIdx * 4;

  unsigned LaneVGPRIdx = Offset / (64 * 4);
  unsigned Lane = (Offset / 4) % 64;

  struct SpilledReg Spill;

  if (!LaneVGPRs.count(LaneVGPRIdx)) {
    unsigned LaneVGPR = findUnusedVGPR(MRI);
    LaneVGPRs[LaneVGPRIdx] = LaneVGPR;
    MRI.setPhysRegUsed(LaneVGPR);

    // Add this register as live-in to all blocks to avoid machine verifer
    // complaining about use of an undefined physical register.
    for (MachineFunction::iterator BI = MF->begin(), BE = MF->end();
         BI != BE; ++BI) {
      BI->addLiveIn(LaneVGPR);
    }
  }

  Spill.VGPR = LaneVGPRs[LaneVGPRIdx];
  Spill.Lane = Lane;
  return Spill;
}
OpenPOWER on IntegriCloud