blob: 1f232dd61a39b2a1332b6ee5eaced5b11271d317 [file] [log] [blame]
Jim Stichnothf7c9a142014-04-29 10:52:43 -07001//===- subzero/src/IceOperand.cpp - High-level operand implementation -----===//
2//
3// The Subzero Code Generator
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Jim Stichnothd97c7df2014-06-04 11:57:08 -070010// This file implements the Operand class and its target-independent
11// subclasses, primarily for the methods of the Variable class.
Jim Stichnothf7c9a142014-04-29 10:52:43 -070012//
13//===----------------------------------------------------------------------===//
14
15#include "IceCfg.h"
16#include "IceInst.h"
17#include "IceOperand.h"
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070018#include "IceTargetLowering.h" // dumping stack/frame pointer register
Jim Stichnothf7c9a142014-04-29 10:52:43 -070019
20namespace Ice {
21
22bool operator<(const RelocatableTuple &A, const RelocatableTuple &B) {
23 if (A.Offset != B.Offset)
24 return A.Offset < B.Offset;
25 if (A.SuppressMangling != B.SuppressMangling)
26 return A.SuppressMangling < B.SuppressMangling;
27 return A.Name < B.Name;
28}
29
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070030bool operator<(const RegWeight &A, const RegWeight &B) {
31 return A.getWeight() < B.getWeight();
32}
33bool operator<=(const RegWeight &A, const RegWeight &B) { return !(B < A); }
34bool operator==(const RegWeight &A, const RegWeight &B) {
35 return !(B < A) && !(A < B);
36}
37
Jim Stichnothd97c7df2014-06-04 11:57:08 -070038void LiveRange::addSegment(InstNumberT Start, InstNumberT End) {
39#ifdef USE_SET
40 RangeElementType Element(Start, End);
41 RangeType::iterator Next = Range.lower_bound(Element);
42 assert(Next == Range.upper_bound(Element)); // Element not already present
43
44 // Beginning of code that merges contiguous segments. TODO: change
45 // "if(true)" to "if(false)" to see if this extra optimization code
46 // gives any performance gain, or is just destabilizing.
47 if (true) {
48 RangeType::iterator FirstDelete = Next;
49 RangeType::iterator Prev = Next;
50 bool hasPrev = (Next != Range.begin());
51 bool hasNext = (Next != Range.end());
52 if (hasPrev)
53 --Prev;
54 // See if Element and Next should be joined.
55 if (hasNext && End == Next->first) {
56 Element.second = Next->second;
57 ++Next;
58 }
59 // See if Prev and Element should be joined.
60 if (hasPrev && Prev->second == Start) {
61 Element.first = Prev->first;
62 FirstDelete = Prev;
63 }
64 Range.erase(FirstDelete, Next);
65 }
66 // End of code that merges contiguous segments.
67
68 Range.insert(Next, Element);
69#else
70 if (Range.empty()) {
71 Range.push_back(RangeElementType(Start, End));
72 return;
73 }
74 // Special case for faking in-arg liveness.
75 if (End < Range.front().first) {
76 assert(Start < 0);
77 Range.push_front(RangeElementType(Start, End));
78 return;
79 }
80 InstNumberT CurrentEnd = Range.back().second;
81 assert(Start >= CurrentEnd);
82 // Check for merge opportunity.
83 if (Start == CurrentEnd) {
84 Range.back().second = End;
85 return;
86 }
87 Range.push_back(RangeElementType(Start, End));
88#endif
89}
90
91// Returns true if this live range ends before Other's live range
92// starts. This means that the highest instruction number in this
93// live range is less than or equal to the lowest instruction number
94// of the Other live range.
95bool LiveRange::endsBefore(const LiveRange &Other) const {
96 // Neither range should be empty, but let's be graceful.
97 if (Range.empty() || Other.Range.empty())
98 return true;
99 InstNumberT MyEnd = (*Range.rbegin()).second;
100 InstNumberT OtherStart = (*Other.Range.begin()).first;
101 return MyEnd <= OtherStart;
102}
103
104// Returns true if there is any overlap between the two live ranges.
105bool LiveRange::overlaps(const LiveRange &Other) const {
106 // Do a two-finger walk through the two sorted lists of segments.
107 RangeType::const_iterator I1 = Range.begin(), I2 = Other.Range.begin();
108 RangeType::const_iterator E1 = Range.end(), E2 = Other.Range.end();
109 while (I1 != E1 && I2 != E2) {
110 if (I1->second <= I2->first) {
111 ++I1;
112 continue;
113 }
114 if (I2->second <= I1->first) {
115 ++I2;
116 continue;
117 }
118 return true;
119 }
120 return false;
121}
122
123bool LiveRange::overlaps(InstNumberT OtherBegin) const {
124 LiveRange Temp;
125 Temp.addSegment(OtherBegin, OtherBegin + 1);
126 return overlaps(Temp);
127}
128
129// Returns true if the live range contains the given instruction
130// number. This is only used for validating the live range
131// calculation.
132bool LiveRange::containsValue(InstNumberT Value) const {
133 for (RangeType::const_iterator I = Range.begin(), E = Range.end(); I != E;
134 ++I) {
135 if (I->first <= Value && Value <= I->second)
136 return true;
137 }
138 return false;
139}
140
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700141void Variable::setUse(const Inst *Inst, const CfgNode *Node) {
142 if (DefNode == NULL)
143 return;
144 if (llvm::isa<InstPhi>(Inst) || Node != DefNode)
145 DefNode = NULL;
146}
147
148void Variable::setDefinition(Inst *Inst, const CfgNode *Node) {
Jim Stichnoth89d79562014-08-27 13:50:03 -0700149 if (DefInst && !DefInst->isDeleted() && DefInst != Inst) {
150 // Detect when a variable is being defined multiple times,
151 // particularly for Phi instruction lowering. If this happens, we
152 // need to lock DefInst to NULL.
153 DefInst = NULL;
154 DefNode = NULL;
155 return;
156 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700157 if (DefNode == NULL)
158 return;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700159 DefInst = Inst;
160 if (Node != DefNode)
161 DefNode = NULL;
162}
163
164void Variable::replaceDefinition(Inst *Inst, const CfgNode *Node) {
165 DefInst = NULL;
166 setDefinition(Inst, Node);
167}
168
Matt Wala45a06232014-07-09 16:33:22 -0700169void Variable::setIsArg(Cfg *Func, bool IsArg) {
170 if (IsArg) {
171 IsArgument = true;
172 if (DefNode == NULL)
173 return;
174 CfgNode *Entry = Func->getEntryNode();
175 if (DefNode == Entry)
176 return;
177 DefNode = NULL;
178 } else {
179 IsArgument = false;
180 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700181}
182
183IceString Variable::getName() const {
184 if (!Name.empty())
185 return Name;
186 char buf[30];
187 snprintf(buf, llvm::array_lengthof(buf), "__%u", getIndex());
188 return buf;
189}
190
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700191Variable Variable::asType(Type Ty) {
192 Variable V(Ty, DefNode, Number, Name);
193 V.RegNum = RegNum;
194 V.StackOffset = StackOffset;
195 return V;
196}
197
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700198// ======================== dump routines ======================== //
199
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700200void Variable::emit(const Cfg *Func) const {
201 Func->getTarget()->emitVariable(this, Func);
202}
203
Jim Stichnoth2e8bfbb2014-09-16 10:16:00 -0700204void Variable::dump(const Cfg *Func, Ostream &Str) const {
205 if (Func == NULL) {
206 Str << "%" << getName();
207 return;
208 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700209 const CfgNode *CurrentNode = Func->getCurrentNode();
210 (void)CurrentNode; // used only in assert()
211 assert(CurrentNode == NULL || DefNode == NULL || DefNode == CurrentNode);
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700212 if (Func->getContext()->isVerbose(IceV_RegOrigins) ||
213 (!hasReg() && !Func->getTarget()->hasComputedFrame()))
214 Str << "%" << getName();
215 if (hasReg()) {
216 if (Func->getContext()->isVerbose(IceV_RegOrigins))
217 Str << ":";
218 Str << Func->getTarget()->getRegName(RegNum, getType());
219 } else if (Func->getTarget()->hasComputedFrame()) {
220 if (Func->getContext()->isVerbose(IceV_RegOrigins))
221 Str << ":";
222 Str << "[" << Func->getTarget()->getRegName(
223 Func->getTarget()->getFrameOrStackReg(), IceType_i32);
224 int32_t Offset = getStackOffset();
225 if (Offset) {
226 if (Offset > 0)
227 Str << "+";
228 Str << Offset;
229 }
230 Str << "]";
231 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700232}
233
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700234void ConstantRelocatable::emit(GlobalContext *Ctx) const {
235 Ostream &Str = Ctx->getStrEmit();
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700236 if (SuppressMangling)
237 Str << Name;
238 else
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700239 Str << Ctx->mangleName(Name);
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700240 if (Offset) {
241 if (Offset > 0)
242 Str << "+";
243 Str << Offset;
244 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700245}
246
Jim Stichnoth2e8bfbb2014-09-16 10:16:00 -0700247void ConstantRelocatable::dump(const Cfg *, Ostream &Str) const {
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700248 Str << "@" << Name;
249 if (Offset)
250 Str << "+" << Offset;
251}
252
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700253void LiveRange::dump(Ostream &Str) const {
254 Str << "(weight=" << Weight << ") ";
255 for (RangeType::const_iterator I = Range.begin(), E = Range.end(); I != E;
256 ++I) {
257 if (I != Range.begin())
258 Str << ", ";
259 Str << "[" << (*I).first << ":" << (*I).second << ")";
260 }
261}
262
263Ostream &operator<<(Ostream &Str, const LiveRange &L) {
264 L.dump(Str);
265 return Str;
266}
267
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700268Ostream &operator<<(Ostream &Str, const RegWeight &W) {
269 if (W.getWeight() == RegWeight::Inf)
270 Str << "Inf";
271 else
272 Str << W.getWeight();
273 return Str;
274}
275
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700276} // end of namespace Ice