OpenASIP  2.0
TCEFrameInfo.cc
Go to the documentation of this file.
1 /*
2  Copyright (c) 2002-2009 Tampere University.
3 
4  This file is part of TTA-Based Codesign Environment (TCE).
5 
6  Permission is hereby granted, free of charge, to any person obtaining a
7  copy of this software and associated documentation files (the "Software"),
8  to deal in the Software without restriction, including without limitation
9  the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  and/or sell copies of the Software, and to permit persons to whom the
11  Software is furnished to do so, subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in
14  all copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  DEALINGS IN THE SOFTWARE.
23  */
24 /**
25  * @file TCEFrameInfo.cpp
26  *
27  * Implementation of TCEFrameLowering class.
28  *
29  * @author Heikki Kultala 2010-2016 (hkultala-no.spam-cs.tut.fi)
30  */
31 
32 #include "TCEFrameInfo.hh"
33 #include <llvm/IR/Function.h>
34 #include <llvm/CodeGen/MachineFrameInfo.h>
35 #include <llvm/CodeGen/MachineInstrBuilder.h>
36 
37 #include "TCEPlugin.hh" // this includes the .inc files
38 
39 using namespace llvm;
40 
41 #include "TCEString.hh"
42 #include "Application.hh"
43 #include "LLVMTCECmdLineOptions.hh"
44 
45 /**
46  * Emits machine function prologue to machine functions.
47  */
48 
49 
50 // Some LLVM 3.9 function wants iterator after the erased instruction.
51 #define ERASE_INSTR_AND_RETURN(I) return MBB.erase(I)
52 
53 #ifdef TARGET64BIT
54 #define ADDIMM TCE::ADD64ssa
55 #define SUBIMM TCE::SUB64ssa
56 #define STREG TCE::ST64ss
57 #define LDREG TCE::LD64ss
58 #define LDRA TCE::LD64RAs
59 #define STRA TCE::ST64RAss
60 #define MOVREG TCE::MOV64ss
61 #else
62 #define ADDIMM TCE::ADDrri
63 #define SUBIMM TCE::SUBrri
64 #define MOVREG TCE::MOVI32rr
65 #ifdef LITTLE_ENDIAN_TARGET
66 #define STREG TCE::ST32rr
67 #define LDREG TCE::LD32rr
68 #define LDRA TCE::LD32RAr
69 #define STRA TCE::ST32RArr
70 #else // big-endian
71 #define STREG TCE::STWrr
72 #define LDREG TCE::LDWrr
73 #define LDRA TCE::LDWRAr
74 #define STRA TCE::STWRArr
75 #endif
76 #endif
77 
78 
79 /**
80  * Eliminates call frame pseudo instructions.
81  *
82  * Stack space is already reserved in caller stack.
83  */
84 MachineBasicBlock::iterator
86  MachineFunction &MF, MachineBasicBlock &MBB,
87  MachineBasicBlock::iterator I) const {
88  if (hasFP(MF)) {
89  int opc = I->getOpcode();
90  // convert stack down to sub
91  if (opc == TCE::ADJCALLSTACKDOWN) {
92  MachineOperand mo1 = I->getOperand(2);
93  MachineOperand mo2 = I->getOperand(3);
94  long val = I->getOperand(0).getImm();
95 
96  if (val == 0) {
98  }
99  auto spOpcAndOffset = tii_.getPointerAdjustment(-val);
100  I->setDesc(tii_.get(std::get<0>(spOpcAndOffset)));
101  I->getOperand(0).ChangeToRegister(mo1.getReg(), mo1.isDef(),
102  false/*mo.isImplicit()*/, mo1.isKill(),
103  false/*dead*/, false/*undef*/,
104  mo1.isDebug());
105  I->getOperand(1).ChangeToRegister(mo2.getReg(), false, false, mo2.isKill(),
106  false, false, mo2.isDebug());
107  I->getOperand(2).ChangeToImmediate(std::get<1>(spOpcAndOffset));
108 
109  // convert stack up to add
110  } else if (opc == TCE::ADJCALLSTACKUP) {
111  MachineOperand mo1 = I->getOperand(2);
112  MachineOperand mo2 = I->getOperand(3);
113  long val = I->getOperand(0).getImm();
114  if (val == 0) {
116  }
117  I->setDesc(tii_.get(ADDIMM));
118  I->getOperand(0).ChangeToRegister(mo1.getReg(), mo1.isDef(),
119  false/*mo.isImplicit()*/, mo1.isKill(),
120  false/*dead*/, false/*undef*/,
121  mo1.isDebug());
122  I->getOperand(1).ChangeToRegister(mo2.getReg(), false, false, mo2.isKill(),
123  false, false, mo2.isDebug());
124  I->getOperand(2).ChangeToImmediate(val);
125  #ifdef LLVM_OLDER_THAN_15
126  I->RemoveOperand(3);
127  #else
128  I->removeOperand(3);
129  #endif
130  }
131  } else {
133  }
134  return I;
135 }
136 #undef ERASE_INSTR_AND_RETURN
137 
138 bool TCEFrameLowering::hasFP(const MachineFunction &MF) const {
139  if (MF.getFrameInfo().hasVarSizedObjects()) {
140  return true;
141  }
142  return false;
143 }
144 
145 bool
146 TCEFrameLowering::containsCall(const MachineFunction& mf) const {
147  for (MachineFunction::const_iterator i = mf.begin(); i != mf.end(); i++) {
148  const MachineBasicBlock& mbb = *i;
149  for (MachineBasicBlock::const_iterator j = mbb.begin();
150  j != mbb.end(); j++){
151  const MachineInstr& ins = *j;
152  if (ins.getOpcode() == TCE::CALL ||
153  ins.getOpcode() == TCE::CALL_MEMrr ||
154  ins.getOpcode() == TCE::CALL_MEMri) {
155  return true;
156  }
157  }
158  }
159  return false;
160 }
161 
162 /**
163  * Emits machine function prologue to machine functions.
164  */
165 void
166 TCEFrameLowering::emitPrologue(MachineFunction& mf, MachineBasicBlock &MBB)
167  const {
168  MachineBasicBlock& mbb = mf.front();
169  MachineFrameInfo& mfi = mf.getFrameInfo();
170  int numBytes = (int)mfi.getStackSize();
171 
172  // this unfortunately return true for inline asm.
173  bool hasCalls = mfi.hasCalls();
174  if (hasCalls) {
175  // so then check again. Return false if only inline asm, no calls.
176  hasCalls = containsCall(mf);
177  }
178 
179  // stack size alignment
180  numBytes = (numBytes + (stackAlignment_-1)) & ~(stackAlignment_-1);
181 
182  // stack size without RA/FP storage
183  int varBytes = numBytes;
184 
185  MachineBasicBlock::iterator ii = mbb.begin();
186 
187  DebugLoc dl = (ii != mbb.end() ?
188  ii->getDebugLoc() : DebugLoc());
189 
190  // No need to save RA if does not call anything or does no return
191  // if (hasCalls && !mf.getFunction()->doesNotReturn()) {
192  // However, there is a bug elsewhere and this triggers it.
193  if (hasCalls) {
194  auto spOpcAndOffset = tii_.getPointerAdjustment(-stackAlignment_);
195  BuildMI(mbb, ii, dl, tii_.get(std::get<0>(spOpcAndOffset)), TCE::SP)
196  .addReg(TCE::SP)
197  .addImm(std::get<1>(spOpcAndOffset));
198 
199  // Save RA to stack.
200  BuildMI(mbb, ii, dl, tii_.get(STRA))
201  .addReg(TCE::SP)
202  .addImm(0)
203  .addReg(TCE::RA)
204  .setMIFlag(MachineInstr::FrameSetup);
205  numBytes += stackAlignment_;
206 
207  // Create metadata which says that this is an RA save
208  MachineBasicBlock::iterator raStore = ii; raStore--;
209  LLVMContext& context = mbb.getParent()->getFunction().getContext();
210  llvm::Metadata* md =
211  llvm::MDString::get(context, "AA_CATEGORY_RA_SAVE_SLOT");
212  MDNode* mdNode =
213  MDNode::get(context, llvm::ArrayRef<llvm::Metadata*>(&md, 1));
214 
215  MachineOperand metaDataOperand = MachineOperand::CreateMetadata(mdNode);
216  raStore->addOperand(metaDataOperand);
217  }
218 
219  if (hasFP(mf)) {
220  // only need to save old FP if this function may return
221  if (!mf.getFunction().doesNotReturn()) {
222  auto spOpcAndOffset = tii_.getPointerAdjustment(-stackAlignment_);
223  BuildMI(mbb, ii, dl, tii_.get(std::get<0>(spOpcAndOffset)),
224  TCE::SP)
225  .addReg(TCE::SP)
226  .addImm(std::get<1>(spOpcAndOffset));
227 
228  BuildMI(mbb, ii, dl, tii_.get(STREG))
229  .addReg(TCE::SP)
230  .addImm(0)
231  .addReg(TCE::FP)
232  .setMIFlag(MachineInstr::FrameSetup);
233 
234  numBytes += stackAlignment_;
235  // Create metadata which says that this is an FP save
236  MachineBasicBlock::iterator fpStore = ii; fpStore--;
237  LLVMContext& context = mbb.getParent()->getFunction().getContext();
238  llvm::Metadata* md =
239  llvm::MDString::get(context, "AA_CATEGORY_FP_SAVE_SLOT");
240  MDNode* mdNode =
241  MDNode::get(context, llvm::ArrayRef<llvm::Metadata*>(&md, 1));
242 
243  MachineOperand metaDataOperand = MachineOperand::CreateMetadata(mdNode);
244  fpStore->addOperand(metaDataOperand);
245  }
246  // if FP used by this function, move SP to FP
247  BuildMI(mbb, ii, dl, tii_.get(MOVREG), TCE::FP).addReg(TCE::SP)
248  .setMIFlag(MachineInstr::FrameSetup);
249  }
250 
251  mfi.setStackSize(numBytes);
252 
253  // Adjust stack pointer
254  if (varBytes != 0) {
255  auto spOpcAndOffset = tii_.getPointerAdjustment(-varBytes);
256  BuildMI(mbb, ii, dl, tii_.get(std::get<0>(spOpcAndOffset)), TCE::SP)
257  .addReg(TCE::SP)
258  .addImm(std::get<1>(spOpcAndOffset));
259  }
260 }
261 
262 /**
263  * Emits machine function epilogue to machine functions.
264  */
265 void
267  MachineFunction& mf, MachineBasicBlock& mbb) const {
268 
269  MachineFrameInfo& mfi = mf.getFrameInfo();
270 
271  MachineBasicBlock::iterator mbbi = std::prev(mbb.end());
272 
273  DebugLoc dl = mbbi->getDebugLoc();
274 
275  if (mbbi->getOpcode() != TCE::RETL) {
276  assert(false && "ERROR: Inserting epilogue w/o return?");
277  }
278 
279  unsigned numBytes = mfi.getStackSize();
280  numBytes = (numBytes + (stackAlignment_-1)) & ~(stackAlignment_-1);
281  unsigned varBytes = numBytes;
282 
283  if (hasFP(mf)) {
284  varBytes -= stackAlignment_;
285  }
286 
287  // this unfortunately return true for inline asm.
288  bool hasCalls = mfi.hasCalls();
289  if (hasCalls) {
290  // so then check again. Return false if only inline asm, no calls.
291  hasCalls = containsCall(mf);
292  if (hasCalls) {
293  varBytes -= stackAlignment_;
294  }
295  }
296 
297  if (hasFP(mf)) {
298  // move FP to SP
299  BuildMI(mbb, mbbi, dl, tii_.get(MOVREG), TCE::SP)
300  .addReg(TCE::FP)
301  .setMIFlag(MachineInstr::FrameSetup);
302 
303  // restore old FP from stack
304  BuildMI(mbb, mbbi, dl, tii_.get(LDREG), TCE::FP)
305  .addReg(TCE::FP)
306  .addImm(0)
307  .setMIFlag(MachineInstr::FrameSetup);
308 
309  // Create metadata which says that this is an FP load
310  MachineBasicBlock::iterator fpLoad = mbbi; fpLoad--;
311 
312  LLVMContext& context =
313  mbb.getParent()->getFunction().getContext();
314 
315  llvm::Metadata* md = llvm::MDString::get(context, "AA_CATEGORY_FP_SAVE_SLOT");
316  MDNode* mdNode = MDNode::get(context, llvm::ArrayRef<llvm::Metadata*>(&md, 1));
317 
318  MachineOperand metaDataOperand = MachineOperand::CreateMetadata(mdNode);
319  fpLoad->addOperand(metaDataOperand);
320 
321  // then the SP adjust
322  BuildMI(mbb, mbbi, dl, tii_.get(ADDIMM), TCE::SP)
323  .addReg(TCE::SP)
324  .addImm(stackAlignment_);
325  } else {
326  // no FP
327  if (varBytes) {
328  BuildMI(mbb, mbbi, dl, tii_.get(ADDIMM), TCE::SP)
329  .addReg(TCE::SP)
330  .addImm(varBytes);
331  }
332  }
333 
334  if (hasCalls) {
335  // Restore RA from stack.
336  BuildMI(mbb, mbbi, dl, tii_.get(LDRA), TCE::RA)
337  .addReg(TCE::SP)
338  .addImm(0)
339  .setMIFlag(MachineInstr::FrameSetup);
340  // Create metadata which says that this is an RA load
341  MachineBasicBlock::iterator raLoad = mbbi; raLoad--;
342 
343  LLVMContext& context =
344  mbb.getParent()->getFunction().getContext();
345 
346  llvm::Metadata* md = llvm::MDString::get(context, "AA_CATEGORY_RA_SAVE_SLOT");
347  MDNode* mdNode = MDNode::get(context, llvm::ArrayRef<llvm::Metadata*>(&md, 1));
348 
349  MachineOperand metaDataOperand = MachineOperand::CreateMetadata(mdNode);
350  raLoad->addOperand(metaDataOperand);
351 
352  // then the SP adjust
353  BuildMI(mbb, mbbi, dl, tii_.get(ADDIMM), TCE::SP)
354  .addReg(TCE::SP)
355  .addImm(stackAlignment_);
356  }
357 }
358 
359 
360 
ADDIMM
#define ADDIMM
Definition: TCEFrameInfo.cc:62
llvm
Definition: InlineAsmParser.hh:49
llvm::TCEFrameLowering::containsCall
bool containsCall(const MachineFunction &mf) const
Definition: TCEFrameInfo.cc:146
llvm::TCEFrameLowering::emitEpilogue
void emitEpilogue(MachineFunction &mf, MachineBasicBlock &MBB) const override
Definition: TCEFrameInfo.cc:266
llvm::TCEFrameLowering::hasFP
bool hasFP(const MachineFunction &MF) const override
Definition: TCEFrameInfo.cc:138
STRA
#define STRA
Definition: TCEFrameInfo.cc:74
llvm::TCEFrameLowering::eliminateCallFramePseudoInstr
MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override
Definition: TCEFrameInfo.cc:85
TCEString.hh
assert
#define assert(condition)
Definition: Application.hh:86
TCEISD::CALL
@ CALL
Definition: TCEISelLowering.hh:65
ERASE_INSTR_AND_RETURN
#define ERASE_INSTR_AND_RETURN(I)
Definition: TCEFrameInfo.cc:51
LDRA
#define LDRA
Definition: TCEFrameInfo.cc:73
MOVREG
#define MOVREG
Definition: TCEFrameInfo.cc:64
LLVMTCECmdLineOptions.hh
Application.hh
STREG
#define STREG
Definition: TCEFrameInfo.cc:71
TCEFrameInfo.hh
RA
#define RA()
Definition: POMGenMacros.hh:393
TCEPlugin.hh
llvm::TCEInstrInfo::getPointerAdjustment
std::tuple< int, int > getPointerAdjustment(int offset) const
Definition: TCEInstrInfo.cc:721
llvm::TCEFrameLowering::stackAlignment_
int stackAlignment_
Definition: TCEFrameInfo.hh:98
llvm::TCEFrameLowering::tii_
const TCEInstrInfo & tii_
Definition: TCEFrameInfo.hh:100
LDREG
#define LDREG
Definition: TCEFrameInfo.cc:72
llvm::TCEFrameLowering::emitPrologue
void emitPrologue(MachineFunction &mf, MachineBasicBlock &MBB) const override
Definition: TCEFrameInfo.cc:166