summaryrefslogtreecommitdiff
path: root/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp
blob: ff7bd7d02693a4209d761dcb420c3b604d11c3e9 (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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//===-- PrologEpilogCodeInserter.cpp - Insert Prolog & Epilog code for fn -===//
// 
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
// 
//===----------------------------------------------------------------------===//
//
// Insert SAVE/RESTORE instructions for the function
//
// Insert prolog code at the unique function entry point.
// Insert epilog code at each function exit point.
// InsertPrologEpilog invokes these only if the function is not compiled
// with the leaf function optimization.
//
//===----------------------------------------------------------------------===//

#include "SparcInternals.h"
#include "SparcRegClassInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineFunctionInfo.h"
#include "llvm/CodeGen/MachineCodeForInstruction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Intrinsics.h"

namespace {
  struct InsertPrologEpilogCode : public MachineFunctionPass {
    const char *getPassName() const { return "Sparc Prolog/Epilog Inserter"; }
    
    bool runOnMachineFunction(MachineFunction &F) {
      if (!F.getInfo()->isCompiledAsLeafMethod()) {
        InsertPrologCode(F);
        InsertEpilogCode(F);
      }
      return false;
    }
    
    void InsertPrologCode(MachineFunction &F);
    void InsertEpilogCode(MachineFunction &F);
  };

}  // End anonymous namespace

//------------------------------------------------------------------------ 
//   Create prolog and epilog code for procedure entry and exit
//------------------------------------------------------------------------ 

void InsertPrologEpilogCode::InsertPrologCode(MachineFunction &MF)
{
  std::vector<MachineInstr*> mvec;
  const TargetMachine &TM = MF.getTarget();
  const TargetFrameInfo& frameInfo = TM.getFrameInfo();
  
  // The second operand is the stack size. If it does not fit in the
  // immediate field, we have to use a free register to hold the size.
  // See the comments below for the choice of this register.
  // 
  unsigned staticStackSize = MF.getInfo()->getStaticStackSize();
  
  if (staticStackSize < (unsigned) frameInfo.getMinStackFrameSize())
    staticStackSize = (unsigned) frameInfo.getMinStackFrameSize();

  if (unsigned padsz = (staticStackSize %
                        (unsigned) frameInfo.getStackFrameSizeAlignment()))
    staticStackSize += frameInfo.getStackFrameSizeAlignment() - padsz;
  
  int32_t C = - (int) staticStackSize;
  int SP = TM.getRegInfo().getStackPointer();
  if (TM.getInstrInfo().constantFitsInImmedField(V9::SAVEi,staticStackSize)) {
    mvec.push_back(BuildMI(V9::SAVEi, 3).addMReg(SP).addSImm(C)
                   .addMReg(SP, MOTy::Def));
  } else {
    // We have to put the stack size value into a register before SAVE.
    // Use register %g1 since it is volatile across calls.  Note that the
    // local (%l) and in (%i) registers cannot be used before the SAVE!
    // Do this by creating a code sequence equivalent to:
    //        SETSW -(stackSize), %g1
    int uregNum = TM.getRegInfo().getUnifiedRegNum(
			 TM.getRegInfo().getRegClassIDOfType(Type::IntTy),
			 SparcIntRegClass::g1);

    MachineInstr* M = BuildMI(V9::SETHI, 2).addSImm(C)
      .addMReg(uregNum, MOTy::Def);
    M->setOperandHi32(0);
    mvec.push_back(M);
    
    M = BuildMI(V9::ORi, 3).addMReg(uregNum).addSImm(C)
      .addMReg(uregNum, MOTy::Def);
    M->setOperandLo32(1);
    mvec.push_back(M);
    
    M = BuildMI(V9::SRAi5, 3).addMReg(uregNum).addZImm(0)
      .addMReg(uregNum, MOTy::Def);
    mvec.push_back(M);
    
    // Now generate the SAVE using the value in register %g1
    M = BuildMI(V9::SAVEr,3).addMReg(SP).addMReg(uregNum).addMReg(SP,MOTy::Def);
    mvec.push_back(M);
  }

  // For varargs function bodies, insert instructions to copy incoming
  // register arguments for the ... list to the stack.
  // The first K=6 arguments are always received via int arg regs
  // (%i0 ... %i5 if K=6) .
  // By copying the varargs arguments to the stack, va_arg() then can
  // simply assume that all vararg arguments are in an array on the stack. 
  // 
  if (MF.getFunction()->getFunctionType()->isVarArg()) {
    int numFixedArgs    = MF.getFunction()->getFunctionType()->getNumParams();
    int numArgRegs      = TM.getRegInfo().getNumOfIntArgRegs();
    if (numFixedArgs < numArgRegs) {
      bool ignore;
      int firstArgReg   = TM.getRegInfo().getUnifiedRegNum(
                             TM.getRegInfo().getRegClassIDOfType(Type::IntTy),
                             SparcIntRegClass::i0);
      int fpReg         = TM.getFrameInfo().getIncomingArgBaseRegNum();
      int argSize       = TM.getFrameInfo().getSizeOfEachArgOnStack();
      int firstArgOffset=TM.getFrameInfo().getFirstIncomingArgOffset(MF,ignore);
      int nextArgOffset = firstArgOffset + numFixedArgs * argSize;

      for (int i=numFixedArgs; i < numArgRegs; ++i) {
        mvec.push_back(BuildMI(V9::STXi, 3).addMReg(firstArgReg+i).
                       addMReg(fpReg).addSImm(nextArgOffset));
        nextArgOffset += argSize;
      }
    }
  }

  MF.front().insert(MF.front().begin(), mvec.begin(), mvec.end());
}

void InsertPrologEpilogCode::InsertEpilogCode(MachineFunction &MF)
{
  const TargetMachine &TM = MF.getTarget();
  const TargetInstrInfo &MII = TM.getInstrInfo();

  for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) {
    MachineBasicBlock &MBB = *I;
    const BasicBlock &BB = *I->getBasicBlock();
    const Instruction *TermInst = (Instruction*)BB.getTerminator();
    if (TermInst->getOpcode() == Instruction::Ret)
    {
      int ZR = TM.getRegInfo().getZeroRegNum();
      MachineInstr *Restore = 
        BuildMI(V9::RESTOREi, 3).addMReg(ZR).addSImm(0).addMReg(ZR, MOTy::Def);
      
      MachineCodeForInstruction &termMvec =
        MachineCodeForInstruction::get(TermInst);
      
      // Remove the NOPs in the delay slots of the return instruction
      unsigned numNOPs = 0;
      while (termMvec.back()->getOpCode() == V9::NOP)
      {
        assert( termMvec.back() == MBB.back());
        delete MBB.pop_back();
        termMvec.pop_back();
        ++numNOPs;
      }
      assert(termMvec.back() == MBB.back());
        
      // Check that we found the right number of NOPs and have the right
      // number of instructions to replace them.
      unsigned ndelays = MII.getNumDelaySlots(termMvec.back()->getOpCode());
      assert(numNOPs == ndelays && "Missing NOPs in delay slots?");
      assert(ndelays == 1 && "Cannot use epilog code for delay slots?");
        
      // Append the epilog code to the end of the basic block.
      MBB.push_back(Restore);
    }
  }
}

FunctionPass *UltraSparc::getPrologEpilogInsertionPass() {
  return new InsertPrologEpilogCode();
}