OLD | NEW |
---|---|
(Empty) | |
1 //===- subzero/src/IceInst.cpp - High-level instruction 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 // | |
10 // This file implements the Inst class, primarily the various | |
11 // subclass constructors and dump routines. | |
12 // | |
13 //===----------------------------------------------------------------------===// | |
14 | |
15 #include "IceCfg.h" | |
16 #include "IceCfgNode.h" | |
17 #include "IceInst.h" | |
18 #include "IceOperand.h" | |
19 | |
20 namespace Ice { | |
21 | |
22 namespace { | |
23 | |
24 const struct { | |
25 const char *DisplayString; | |
26 bool IsCommutative; | |
27 } InstArithmeticAttributes[] = { | |
28 #define X(tag, str, commutative) \ | |
29 { str, commutative } \ | |
30 , | |
31 ICEINSTARITHMETIC_TABLE | |
32 #undef X | |
33 }; | |
34 const size_t InstArithmeticAttributesSize = | |
35 sizeof(InstArithmeticAttributes) / sizeof(*InstArithmeticAttributes); | |
JF
2014/04/26 20:20:56
array_lengthof
Jim Stichnoth
2014/04/27 15:04:57
Strangely, this doesn't work.
const size_t InstAr
Jim Stichnoth
2014/04/27 15:25:22
Done. Turns out you can't use array_lengthof for
| |
36 | |
37 const struct { | |
38 const char *DisplayString; | |
39 } InstCastAttributes[] = { | |
40 #define X(tag, str) \ | |
41 { str } \ | |
42 , | |
43 ICEINSTCAST_TABLE | |
44 #undef X | |
45 }; | |
46 const size_t InstCastAttributesSize = | |
47 sizeof(InstCastAttributes) / sizeof(*InstCastAttributes); | |
JF
2014/04/26 20:20:56
ditto
Jim Stichnoth
2014/04/27 15:25:22
Done.
| |
48 | |
49 const struct { | |
50 const char *DisplayString; | |
51 } InstFcmpAttributes[] = { | |
52 #define X(tag, str) \ | |
53 { str } \ | |
54 , | |
55 ICEINSTFCMP_TABLE | |
56 #undef X | |
57 }; | |
58 const size_t InstFcmpAttributesSize = | |
59 sizeof(InstFcmpAttributes) / sizeof(*InstFcmpAttributes); | |
JF
2014/04/26 20:20:56
ditto
Jim Stichnoth
2014/04/27 15:25:22
Done.
| |
60 | |
61 const struct { | |
62 const char *DisplayString; | |
63 } InstIcmpAttributes[] = { | |
64 #define X(tag, str) \ | |
65 { str } \ | |
66 , | |
67 ICEINSTICMP_TABLE | |
68 #undef X | |
69 }; | |
70 const size_t InstIcmpAttributesSize = | |
71 sizeof(InstIcmpAttributes) / sizeof(*InstIcmpAttributes); | |
JF
2014/04/26 20:20:56
ditto
Jim Stichnoth
2014/04/27 15:25:22
Done.
| |
72 | |
73 } // end of anonymous namespace | |
74 | |
75 Inst::Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) | |
76 : Kind(Kind), Number(Func->newInstNumber()), Deleted(false), | |
77 HasSideEffects(false), Dest(Dest), MaxSrcs(MaxSrcs), NumSrcs(0), | |
78 Srcs(Func->allocateArrayOf<Operand *>(MaxSrcs)) {} | |
79 | |
80 void Inst::updateVars(CfgNode *Node) { | |
81 if (Dest) | |
82 Dest->setDefinition(this, Node); | |
83 | |
84 SizeT VarIndex = 0; | |
85 for (SizeT I = 0; I < getSrcSize(); ++I) { | |
86 Operand *Src = getSrc(I); | |
87 SizeT NumVars = Src->getNumVars(); | |
88 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { | |
89 Variable *Var = Src->getVar(J); | |
90 Var->setUse(this, Node); | |
91 } | |
92 } | |
93 } | |
94 | |
95 InstAlloca::InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t Align, | |
96 Variable *Dest) | |
97 : Inst(Func, Inst::Alloca, 1, Dest), Align(Align) { | |
98 // Verify Align is 0 or a power of 2. | |
99 assert(Align == 0 || !(Align & (Align - 1))); | |
JF
2014/04/26 20:20:56
llvm::isPowerOf2_32
Jim Stichnoth
2014/04/27 15:04:57
Done.
| |
100 addSource(ByteCount); | |
101 } | |
102 | |
103 InstArithmetic::InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, | |
104 Operand *Source1, Operand *Source2) | |
105 : Inst(Func, Inst::Arithmetic, 2, Dest), Op(Op) { | |
106 addSource(Source1); | |
107 addSource(Source2); | |
108 } | |
109 | |
110 bool InstArithmetic::isCommutative() const { | |
111 return InstArithmeticAttributes[getOp()].IsCommutative; | |
112 } | |
113 | |
114 InstAssign::InstAssign(Cfg *Func, Variable *Dest, Operand *Source) | |
115 : Inst(Func, Inst::Assign, 1, Dest) { | |
116 addSource(Source); | |
117 } | |
118 | |
119 // If TargetTrue==TargetFalse, we turn it into an unconditional | |
120 // branch. This ensures that, along with the 'switch' instruction | |
121 // semantics, there is at most one edge from one node to another. | |
122 InstBr::InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, | |
123 CfgNode *TargetFalse) | |
124 : Inst(Func, Inst::Br, 1, NULL), TargetFalse(TargetFalse), | |
125 TargetTrue(TargetTrue) { | |
126 if (TargetTrue == TargetFalse) { | |
127 TargetTrue = NULL; // turn into unconditional version | |
128 } else { | |
129 addSource(Source); | |
130 } | |
131 } | |
132 | |
133 InstBr::InstBr(Cfg *Func, CfgNode *Target) | |
134 : Inst(Func, Inst::Br, 0, NULL), TargetFalse(Target), TargetTrue(NULL) {} | |
135 | |
136 NodeList InstBr::getTerminatorEdges() const { | |
137 NodeList OutEdges; | |
138 OutEdges.push_back(TargetFalse); | |
139 if (TargetTrue) | |
140 OutEdges.push_back(TargetTrue); | |
141 return OutEdges; | |
142 } | |
143 | |
144 InstCast::InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source) | |
145 : Inst(Func, Inst::Cast, 1, Dest), CastKind(CastKind) { | |
146 addSource(Source); | |
147 } | |
148 | |
149 InstFcmp::InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1, | |
150 Operand *Source2) | |
151 : Inst(Func, Inst::Fcmp, 2, Dest), Condition(Condition) { | |
152 addSource(Source1); | |
153 addSource(Source2); | |
154 } | |
155 | |
156 InstIcmp::InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1, | |
157 Operand *Source2) | |
158 : Inst(Func, Inst::Icmp, 2, Dest), Condition(Condition) { | |
159 addSource(Source1); | |
160 addSource(Source2); | |
161 } | |
162 | |
163 InstLoad::InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr) | |
164 : Inst(Func, Inst::Load, 1, Dest) { | |
165 addSource(SourceAddr); | |
166 } | |
167 | |
168 InstPhi::InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest) | |
169 : Inst(Func, Phi, MaxSrcs, Dest) { | |
170 Labels = Func->allocateArrayOf<CfgNode *>(MaxSrcs); | |
171 } | |
172 | |
173 // TODO: A Switch instruction (and maybe others) can add duplicate | |
174 // edges. We may want to de-dup Phis and validate consistency (i.e., | |
175 // the source operands are the same for duplicate edges), though it | |
176 // seems the current lowering code is OK with this situation. | |
177 void InstPhi::addArgument(Operand *Source, CfgNode *Label) { | |
178 Labels[getSrcSize()] = Label; | |
179 addSource(Source); | |
180 } | |
181 | |
182 InstRet::InstRet(Cfg *Func, Operand *RetValue) | |
183 : Inst(Func, Ret, RetValue ? 1 : 0, NULL) { | |
184 if (RetValue) | |
185 addSource(RetValue); | |
186 } | |
187 | |
188 InstSelect::InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, | |
189 Operand *SourceTrue, Operand *SourceFalse) | |
190 : Inst(Func, Inst::Select, 3, Dest) { | |
191 assert(Condition->getType() == IceType_i1); | |
192 addSource(Condition); | |
193 addSource(SourceTrue); | |
194 addSource(SourceFalse); | |
195 } | |
196 | |
197 InstStore::InstStore(Cfg *Func, Operand *Data, Operand *Addr) | |
198 : Inst(Func, Inst::Store, 2, NULL) { | |
199 addSource(Data); | |
200 addSource(Addr); | |
201 } | |
202 | |
203 InstSwitch::InstSwitch(Cfg *Func, SizeT NumCases, Operand *Source, | |
204 CfgNode *LabelDefault) | |
205 : Inst(Func, Inst::Switch, 1, NULL), LabelDefault(LabelDefault), | |
206 NumCases(NumCases) { | |
207 addSource(Source); | |
208 Values = Func->allocateArrayOf<uint64_t>(NumCases); | |
209 Labels = Func->allocateArrayOf<CfgNode *>(NumCases); | |
210 // Initialize in case buggy code doesn't set all entries | |
211 for (SizeT I = 0; I < NumCases; ++I) { | |
212 Values[I] = 0; | |
213 Labels[I] = NULL; | |
214 } | |
215 } | |
216 | |
217 void InstSwitch::addBranch(SizeT CaseIndex, uint64_t Value, CfgNode *Label) { | |
218 assert(CaseIndex < NumCases); | |
219 Values[CaseIndex] = Value; | |
220 Labels[CaseIndex] = Label; | |
221 } | |
222 | |
223 NodeList InstSwitch::getTerminatorEdges() const { | |
224 NodeList OutEdges; | |
225 OutEdges.push_back(LabelDefault); | |
226 for (SizeT I = 0; I < NumCases; ++I) { | |
227 OutEdges.push_back(Labels[I]); | |
228 } | |
229 return OutEdges; | |
230 } | |
231 | |
232 InstUnreachable::InstUnreachable(Cfg *Func) | |
233 : Inst(Func, Inst::Unreachable, 0, NULL) {} | |
234 | |
235 // ======================== Dump routines ======================== // | |
236 | |
237 void Inst::dumpDecorated(const Cfg *Func) const { | |
238 Ostream &Str = Func->getContext()->getStrDump(); | |
239 if (!Func->getContext()->isVerbose(IceV_Deleted) && isDeleted()) | |
240 return; | |
241 if (Func->getContext()->isVerbose(IceV_InstNumbers)) { | |
242 char buf[30]; | |
243 int32_t Number = getNumber(); | |
244 if (Number < 0) | |
245 snprintf(buf, llvm::array_lengthof(buf), "[XXX]"); | |
246 else | |
247 snprintf(buf, llvm::array_lengthof(buf), "[%3d]", Number); | |
248 Str << buf; | |
249 } | |
250 Str << " "; | |
251 if (isDeleted()) | |
252 Str << " //"; | |
253 dump(Func); | |
254 Str << "\n"; | |
255 } | |
256 | |
257 void Inst::dump(const Cfg *Func) const { | |
258 Ostream &Str = Func->getContext()->getStrDump(); | |
259 dumpDest(Func); | |
260 Str << " =~ "; | |
261 dumpSources(Func); | |
262 } | |
263 | |
264 void Inst::dumpSources(const Cfg *Func) const { | |
265 Ostream &Str = Func->getContext()->getStrDump(); | |
266 for (SizeT I = 0; I < getSrcSize(); ++I) { | |
267 if (I > 0) | |
268 Str << ", "; | |
269 getSrc(I)->dump(Func); | |
270 } | |
271 } | |
272 | |
273 void Inst::dumpDest(const Cfg *Func) const { | |
274 if (getDest()) | |
275 getDest()->dump(Func); | |
276 } | |
277 | |
278 void InstAlloca::dump(const Cfg *Func) const { | |
279 Ostream &Str = Func->getContext()->getStrDump(); | |
280 dumpDest(Func); | |
281 Str << " = alloca i8, i32 "; | |
282 getSizeInBytes()->dump(Func); | |
283 Str << ", align " << Align; | |
284 } | |
285 | |
286 void InstArithmetic::dump(const Cfg *Func) const { | |
287 Ostream &Str = Func->getContext()->getStrDump(); | |
288 dumpDest(Func); | |
289 Str << " = " << InstArithmeticAttributes[getOp()].DisplayString << " " | |
290 << getDest()->getType() << " "; | |
291 dumpSources(Func); | |
292 } | |
293 | |
294 void InstAssign::dump(const Cfg *Func) const { | |
295 Ostream &Str = Func->getContext()->getStrDump(); | |
296 dumpDest(Func); | |
297 Str << " = " << getDest()->getType() << " "; | |
298 dumpSources(Func); | |
299 } | |
300 | |
301 void InstBr::dump(const Cfg *Func) const { | |
302 Ostream &Str = Func->getContext()->getStrDump(); | |
303 dumpDest(Func); | |
304 Str << "br "; | |
305 if (!isUnconditional()) { | |
306 Str << "i1 "; | |
307 getCondition()->dump(Func); | |
308 Str << ", label %" << getTargetTrue()->getName() << ", "; | |
309 } | |
310 Str << "label %" << getTargetFalse()->getName(); | |
311 } | |
312 | |
313 void InstCall::dump(const Cfg *Func) const { | |
314 Ostream &Str = Func->getContext()->getStrDump(); | |
315 if (getDest()) { | |
316 dumpDest(Func); | |
317 Str << " = "; | |
318 } | |
319 Str << "call "; | |
320 if (getDest()) | |
321 Str << getDest()->getType(); | |
322 else | |
323 Str << "void"; | |
324 Str << " "; | |
325 getCallTarget()->dump(Func); | |
326 Str << "("; | |
327 for (SizeT I = 0; I < getNumArgs(); ++I) { | |
328 if (I > 0) | |
329 Str << ", "; | |
330 Str << getArg(I)->getType() << " "; | |
331 getArg(I)->dump(Func); | |
332 } | |
333 Str << ")"; | |
334 } | |
335 | |
336 void InstCast::dump(const Cfg *Func) const { | |
337 Ostream &Str = Func->getContext()->getStrDump(); | |
338 dumpDest(Func); | |
339 Str << " = " << InstCastAttributes[getCastKind()].DisplayString << " " | |
340 << getSrc(0)->getType() << " "; | |
341 dumpSources(Func); | |
342 Str << " to " << getDest()->getType(); | |
343 } | |
344 | |
345 void InstIcmp::dump(const Cfg *Func) const { | |
346 Ostream &Str = Func->getContext()->getStrDump(); | |
347 dumpDest(Func); | |
348 Str << " = icmp " << InstIcmpAttributes[getCondition()].DisplayString << " " | |
349 << getSrc(0)->getType() << " "; | |
350 dumpSources(Func); | |
351 } | |
352 | |
353 void InstFcmp::dump(const Cfg *Func) const { | |
354 Ostream &Str = Func->getContext()->getStrDump(); | |
355 dumpDest(Func); | |
356 Str << " = fcmp " << InstFcmpAttributes[getCondition()].DisplayString << " " | |
357 << getSrc(0)->getType() << " "; | |
358 dumpSources(Func); | |
359 } | |
360 | |
361 void InstLoad::dump(const Cfg *Func) const { | |
362 Ostream &Str = Func->getContext()->getStrDump(); | |
363 dumpDest(Func); | |
364 Type Ty = getDest()->getType(); | |
365 Str << " = load " << Ty << "* "; | |
366 dumpSources(Func); | |
367 switch (Ty) { | |
368 case IceType_f32: | |
369 Str << ", align 4"; | |
370 break; | |
371 case IceType_f64: | |
372 Str << ", align 8"; | |
373 break; | |
374 default: | |
375 Str << ", align 1"; | |
376 break; | |
JF
2014/04/26 20:20:56
Won't you need to factor alignment out at some poi
Jim Stichnoth
2014/04/27 15:04:57
Good point. I added alignment to the IceTypes.def
| |
377 } | |
378 } | |
379 | |
380 void InstStore::dump(const Cfg *Func) const { | |
381 Ostream &Str = Func->getContext()->getStrDump(); | |
382 Type Ty = getData()->getType(); | |
383 Str << "store " << Ty << " "; | |
384 getData()->dump(Func); | |
385 Str << ", " << Ty << "* "; | |
386 getAddr()->dump(Func); | |
387 Str << ", align "; | |
388 switch (Ty) { | |
389 case IceType_f32: | |
390 Str << "4"; | |
391 break; | |
392 case IceType_f64: | |
393 Str << "8"; | |
394 break; | |
395 default: | |
396 Str << "1"; | |
397 break; | |
398 } | |
399 } | |
400 | |
401 void InstSwitch::dump(const Cfg *Func) const { | |
402 Ostream &Str = Func->getContext()->getStrDump(); | |
403 Type Ty = getComparison()->getType(); | |
404 Str << "switch " << Ty << " "; | |
405 getSrc(0)->dump(Func); | |
406 Str << ", label %" << getLabelDefault()->getName() << " [\n"; | |
407 for (SizeT I = 0; I < getNumCases(); ++I) { | |
408 Str << " " << Ty << " " << getValue(I) << ", label %" | |
409 << getLabel(I)->getName() << "\n"; | |
410 } | |
411 Str << " ]"; | |
412 } | |
413 | |
414 void InstPhi::dump(const Cfg *Func) const { | |
415 Ostream &Str = Func->getContext()->getStrDump(); | |
416 dumpDest(Func); | |
417 Str << " = phi " << getDest()->getType() << " "; | |
418 for (SizeT I = 0; I < getSrcSize(); ++I) { | |
419 if (I > 0) | |
420 Str << ", "; | |
421 Str << "[ "; | |
422 getSrc(I)->dump(Func); | |
423 Str << ", %" << Labels[I]->getName() << " ]"; | |
424 } | |
425 } | |
426 | |
427 void InstRet::dump(const Cfg *Func) const { | |
428 Ostream &Str = Func->getContext()->getStrDump(); | |
429 Type Ty = hasRetValue() ? getSrc(0)->getType() : IceType_void; | |
430 Str << "ret " << Ty; | |
431 if (hasRetValue()) { | |
432 Str << " "; | |
433 dumpSources(Func); | |
434 } | |
435 } | |
436 | |
437 void InstSelect::dump(const Cfg *Func) const { | |
438 Ostream &Str = Func->getContext()->getStrDump(); | |
439 dumpDest(Func); | |
440 Operand *Condition = getCondition(); | |
441 Operand *TrueOp = getTrueOperand(); | |
442 Operand *FalseOp = getFalseOperand(); | |
443 Str << " = select " << Condition->getType() << " "; | |
444 Condition->dump(Func); | |
445 Str << ", " << TrueOp->getType() << " "; | |
446 TrueOp->dump(Func); | |
447 Str << ", " << FalseOp->getType() << " "; | |
448 FalseOp->dump(Func); | |
449 } | |
450 | |
451 void InstUnreachable::dump(const Cfg *Func) const { | |
452 Ostream &Str = Func->getContext()->getStrDump(); | |
453 Str << "unreachable"; | |
454 } | |
455 | |
456 } // end of namespace Ice | |
OLD | NEW |