OpenASIP 2.2
Loading...
Searching...
No Matches
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
39using namespace llvm;
40
41#include "TCEString.hh"
42#include "Application.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 */
84MachineBasicBlock::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
138bool TCEFrameLowering::hasFP(const MachineFunction &MF) const {
139 if (MF.getFrameInfo().hasVarSizedObjects()) {
140 return true;
141 }
142 return false;
143}
144
145bool
146TCEFrameLowering::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 */
165void
166TCEFrameLowering::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 */
265void
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
#define assert(condition)
#define STRA
#define MOVREG
#define ADDIMM
#define LDRA
#define STREG
#define LDREG
#define ERASE_INSTR_AND_RETURN(I)
void emitEpilogue(MachineFunction &mf, MachineBasicBlock &MBB) const override
bool hasFP(const MachineFunction &MF) const override
bool containsCall(const MachineFunction &mf) const
const TCEInstrInfo & tii_
void emitPrologue(MachineFunction &mf, MachineBasicBlock &MBB) const override
MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override
std::tuple< int, int > getPointerAdjustment(int offset) const