Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: src/IceInst.h

Issue 205613002: Initial skeleton of Subzero. (Closed) Base URL: https://gerrit.chromium.org/gerrit/p/native_client/pnacl-subzero.git@master
Patch Set: Use non-anonymous structs so that array_lengthof works Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/IceGlobalContext.cpp ('k') | src/IceInst.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 //===- subzero/src/IceInst.h - High-level instructions ----------*- C++ -*-===//
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 declares the Inst class and its target-independent
11 // subclasses, which represent the high-level Vanilla ICE instructions
12 // and map roughly 1:1 to LLVM instructions.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #ifndef SUBZERO_SRC_ICEINST_H
17 #define SUBZERO_SRC_ICEINST_H
18
19 #include "IceDefs.h"
20 #include "IceInst.def"
21 #include "IceTypes.h"
22
23 // TODO: The Cfg structure, and instructions in particular, need to be
24 // validated for things like valid operand types, valid branch
25 // targets, proper ordering of Phi and non-Phi instructions, etc.
26 // Most of the validity checking will be done in the bitcode reader.
27 // We need a list of everything that should be validated, and tests
28 // for each.
29
30 namespace Ice {
31
32 class Inst {
33 public:
34 enum InstKind {
35 // Arbitrary (alphabetical) order, except put Unreachable first.
36 Unreachable,
37 Alloca,
38 Arithmetic,
39 Assign, // not part of LLVM/PNaCl bitcode
40 Br,
41 Call,
42 Cast,
43 Fcmp,
44 Icmp,
45 Load,
46 Phi,
47 Ret,
48 Select,
49 Store,
50 Switch
51 };
52 InstKind getKind() const { return Kind; }
53
54 int32_t getNumber() const { return Number; }
55
56 bool isDeleted() const { return Deleted; }
57 void setDeleted() { Deleted = true; }
58
59 bool hasSideEffects() const { return HasSideEffects; }
60
61 Variable *getDest() const { return Dest; }
62
63 SizeT getSrcSize() const { return NumSrcs; }
64 Operand *getSrc(SizeT I) const {
65 assert(I < getSrcSize());
66 return Srcs[I];
67 }
68
69 // Returns a list of out-edges corresponding to a terminator
70 // instruction, which is the last instruction of the block.
71 virtual NodeList getTerminatorEdges() const {
72 // All valid terminator instructions override this method. For
73 // the default implementation, we assert in case some CfgNode
74 // is constructed without a terminator instruction at the end.
75 llvm_unreachable(
76 "getTerminatorEdges() called on a non-terminator instruction");
77 return NodeList();
78 }
79
80 // Updates the status of the Variables contained within the
81 // instruction. In particular, it marks where the Dest variable is
82 // first assigned, and it tracks whether variables are live across
83 // basic blocks, i.e. used in a different block from their definition.
84 void updateVars(CfgNode *Node);
85
86 virtual void dump(const Cfg *Func) const;
87 void dumpDecorated(const Cfg *Func) const;
88 void dumpSources(const Cfg *Func) const;
89 void dumpDest(const Cfg *Func) const;
90
91 virtual ~Inst() {}
92
93 protected:
94 Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest);
95 void addSource(Operand *Src) {
96 assert(Src);
97 assert(NumSrcs < MaxSrcs);
98 Srcs[NumSrcs++] = Src;
99 }
100 // The destroy() method lets the instruction cleanly release any
101 // memory that was allocated via the Cfg's allocator.
102 virtual void destroy(Cfg *Func) { Func->deallocateArrayOf<Operand *>(Srcs); }
103
104 const InstKind Kind;
105 // Number is the instruction number for describing live ranges.
106 int32_t Number;
107 // Deleted means irrevocably deleted.
108 bool Deleted;
109 // HasSideEffects means the instruction is something like a function
110 // call or a volatile load that can't be removed even if its Dest
111 // variable is not live.
112 bool HasSideEffects;
113
114 Variable *Dest;
115 const SizeT MaxSrcs; // only used for assert
116 SizeT NumSrcs;
117 Operand **Srcs;
118
119 private:
120 Inst(const Inst &) LLVM_DELETED_FUNCTION;
121 Inst &operator=(const Inst &) LLVM_DELETED_FUNCTION;
122 };
123
124 // Alloca instruction. This captures the size in bytes as getSrc(0),
125 // and the required alignment in bytes. The alignment must be either
126 // 0 (no alignment required) or a power of 2.
127 class InstAlloca : public Inst {
128 public:
129 static InstAlloca *create(Cfg *Func, Operand *ByteCount,
130 uint32_t AlignInBytes, Variable *Dest) {
131 return new (Func->allocateInst<InstAlloca>())
132 InstAlloca(Func, ByteCount, AlignInBytes, Dest);
133 }
134 uint32_t getAlignInBytes() const { return AlignInBytes; }
135 Operand *getSizeInBytes() const { return getSrc(0); }
136 virtual void dump(const Cfg *Func) const;
137 static bool classof(const Inst *Inst) { return Inst->getKind() == Alloca; }
138
139 private:
140 InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes,
141 Variable *Dest);
142 InstAlloca(const InstAlloca &) LLVM_DELETED_FUNCTION;
143 InstAlloca &operator=(const InstAlloca &) LLVM_DELETED_FUNCTION;
144 virtual ~InstAlloca() {}
145 const uint32_t AlignInBytes;
146 };
147
148 // Binary arithmetic instruction. The source operands are captured in
149 // getSrc(0) and getSrc(1).
150 class InstArithmetic : public Inst {
151 public:
152 enum OpKind {
153 #define X(tag, str, commutative) tag,
154 ICEINSTARITHMETIC_TABLE
155 #undef X
156 };
157 static InstArithmetic *create(Cfg *Func, OpKind Op, Variable *Dest,
158 Operand *Source1, Operand *Source2) {
159 return new (Func->allocateInst<InstArithmetic>())
160 InstArithmetic(Func, Op, Dest, Source1, Source2);
161 }
162 OpKind getOp() const { return Op; }
163 bool isCommutative() const;
164 virtual void dump(const Cfg *Func) const;
165 static bool classof(const Inst *Inst) {
166 return Inst->getKind() == Arithmetic;
167 }
168
169 private:
170 InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, Operand *Source1,
171 Operand *Source2);
172 InstArithmetic(const InstArithmetic &) LLVM_DELETED_FUNCTION;
173 InstArithmetic &operator=(const InstArithmetic &) LLVM_DELETED_FUNCTION;
174 virtual ~InstArithmetic() {}
175
176 const OpKind Op;
177 };
178
179 // Assignment instruction. The source operand is captured in
180 // getSrc(0). This is not part of the LLVM bitcode, but is a useful
181 // abstraction for some of the lowering. E.g., if Phi instruction
182 // lowering happens before target lowering, or for representing an
183 // Inttoptr instruction, or as an intermediate step for lowering a
184 // Load instruction.
185 class InstAssign : public Inst {
186 public:
187 static InstAssign *create(Cfg *Func, Variable *Dest, Operand *Source) {
188 return new (Func->allocateInst<InstAssign>())
189 InstAssign(Func, Dest, Source);
190 }
191 virtual void dump(const Cfg *Func) const;
192 static bool classof(const Inst *Inst) { return Inst->getKind() == Assign; }
193
194 private:
195 InstAssign(Cfg *Func, Variable *Dest, Operand *Source);
196 InstAssign(const InstAssign &) LLVM_DELETED_FUNCTION;
197 InstAssign &operator=(const InstAssign &) LLVM_DELETED_FUNCTION;
198 virtual ~InstAssign() {}
199 };
200
201 // Branch instruction. This represents both conditional and
202 // unconditional branches.
203 class InstBr : public Inst {
204 public:
205 // Create a conditional branch. If TargetTrue==TargetFalse, it is
206 // optimized to an unconditional branch.
207 static InstBr *create(Cfg *Func, Operand *Source, CfgNode *TargetTrue,
208 CfgNode *TargetFalse) {
209 return new (Func->allocateInst<InstBr>())
210 InstBr(Func, Source, TargetTrue, TargetFalse);
211 }
212 // Create an unconditional branch.
213 static InstBr *create(Cfg *Func, CfgNode *Target) {
214 return new (Func->allocateInst<InstBr>()) InstBr(Func, Target);
215 }
216 bool isUnconditional() const { return getTargetTrue() == NULL; }
217 Operand *getCondition() const {
218 assert(!isUnconditional());
219 return getSrc(0);
220 }
221 CfgNode *getTargetTrue() const { return TargetTrue; }
222 CfgNode *getTargetFalse() const { return TargetFalse; }
223 CfgNode *getTargetUnconditional() const {
224 assert(isUnconditional());
225 return getTargetFalse();
226 }
227 virtual NodeList getTerminatorEdges() const;
228 virtual void dump(const Cfg *Func) const;
229 static bool classof(const Inst *Inst) { return Inst->getKind() == Br; }
230
231 private:
232 // Conditional branch
233 InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, CfgNode *TargetFalse);
234 // Unconditional branch
235 InstBr(Cfg *Func, CfgNode *Target);
236 InstBr(const InstBr &) LLVM_DELETED_FUNCTION;
237 InstBr &operator=(const InstBr &) LLVM_DELETED_FUNCTION;
238 virtual ~InstBr() {}
239
240 CfgNode *const TargetFalse; // Doubles as unconditional branch target
241 CfgNode *const TargetTrue; // NULL if unconditional branch
242 };
243
244 // Call instruction. The call target is captured as getSrc(0), and
245 // arg I is captured as getSrc(I+1).
246 class InstCall : public Inst {
247 public:
248 static InstCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest,
249 Operand *CallTarget) {
250 return new (Func->allocateInst<InstCall>())
251 InstCall(Func, NumArgs, Dest, CallTarget);
252 }
253 void addArg(Operand *Arg) { addSource(Arg); }
254 Operand *getCallTarget() const { return getSrc(0); }
255 Operand *getArg(SizeT I) const { return getSrc(I + 1); }
256 SizeT getNumArgs() const { return getSrcSize() - 1; }
257 virtual void dump(const Cfg *Func) const;
258 static bool classof(const Inst *Inst) { return Inst->getKind() == Call; }
259
260 private:
261 InstCall(Cfg *Func, SizeT NumArgs, Variable *Dest, Operand *CallTarget)
262 : Inst(Func, Inst::Call, NumArgs + 1, Dest) {
263 // Set HasSideEffects so that the call instruction can't be
264 // dead-code eliminated. Don't set this for a deletable intrinsic
265 // call.
266 HasSideEffects = true;
267 addSource(CallTarget);
268 }
269 InstCall(const InstCall &) LLVM_DELETED_FUNCTION;
270 InstCall &operator=(const InstCall &) LLVM_DELETED_FUNCTION;
271 virtual ~InstCall() {}
272 };
273
274 // Cast instruction (a.k.a. conversion operation).
275 class InstCast : public Inst {
276 public:
277 enum OpKind {
278 #define X(tag, str) tag,
279 ICEINSTCAST_TABLE
280 #undef X
281 };
282 static InstCast *create(Cfg *Func, OpKind CastKind, Variable *Dest,
283 Operand *Source) {
284 return new (Func->allocateInst<InstCast>())
285 InstCast(Func, CastKind, Dest, Source);
286 }
287 OpKind getCastKind() const { return CastKind; }
288 virtual void dump(const Cfg *Func) const;
289 static bool classof(const Inst *Inst) { return Inst->getKind() == Cast; }
290
291 private:
292 InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source);
293 InstCast(const InstCast &) LLVM_DELETED_FUNCTION;
294 InstCast &operator=(const InstCast &) LLVM_DELETED_FUNCTION;
295 virtual ~InstCast() {}
296 const OpKind CastKind;
297 };
298
299 // Floating-point comparison instruction. The source operands are
300 // captured in getSrc(0) and getSrc(1).
301 class InstFcmp : public Inst {
302 public:
303 enum FCond {
304 #define X(tag, str) tag,
305 ICEINSTFCMP_TABLE
306 #undef X
307 };
308 static InstFcmp *create(Cfg *Func, FCond Condition, Variable *Dest,
309 Operand *Source1, Operand *Source2) {
310 return new (Func->allocateInst<InstFcmp>())
311 InstFcmp(Func, Condition, Dest, Source1, Source2);
312 }
313 FCond getCondition() const { return Condition; }
314 virtual void dump(const Cfg *Func) const;
315 static bool classof(const Inst *Inst) { return Inst->getKind() == Fcmp; }
316
317 private:
318 InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1,
319 Operand *Source2);
320 InstFcmp(const InstFcmp &) LLVM_DELETED_FUNCTION;
321 InstFcmp &operator=(const InstFcmp &) LLVM_DELETED_FUNCTION;
322 virtual ~InstFcmp() {}
323 const FCond Condition;
324 };
325
326 // Integer comparison instruction. The source operands are captured
327 // in getSrc(0) and getSrc(1).
328 class InstIcmp : public Inst {
329 public:
330 enum ICond {
331 #define X(tag, str) tag,
332 ICEINSTICMP_TABLE
333 #undef X
334 };
335 static InstIcmp *create(Cfg *Func, ICond Condition, Variable *Dest,
336 Operand *Source1, Operand *Source2) {
337 return new (Func->allocateInst<InstIcmp>())
338 InstIcmp(Func, Condition, Dest, Source1, Source2);
339 }
340 ICond getCondition() const { return Condition; }
341 virtual void dump(const Cfg *Func) const;
342 static bool classof(const Inst *Inst) { return Inst->getKind() == Icmp; }
343
344 private:
345 InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1,
346 Operand *Source2);
347 InstIcmp(const InstIcmp &) LLVM_DELETED_FUNCTION;
348 InstIcmp &operator=(const InstIcmp &) LLVM_DELETED_FUNCTION;
349 virtual ~InstIcmp() {}
350 const ICond Condition;
351 };
352
353 // Load instruction. The source address is captured in getSrc(0).
354 class InstLoad : public Inst {
355 public:
356 static InstLoad *create(Cfg *Func, Variable *Dest, Operand *SourceAddr) {
357 return new (Func->allocateInst<InstLoad>())
358 InstLoad(Func, Dest, SourceAddr);
359 }
360 Operand *getSourceAddress() const { return getSrc(0); }
361 virtual void dump(const Cfg *Func) const;
362 static bool classof(const Inst *Inst) { return Inst->getKind() == Load; }
363
364 private:
365 InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr);
366 InstLoad(const InstLoad &) LLVM_DELETED_FUNCTION;
367 InstLoad &operator=(const InstLoad &) LLVM_DELETED_FUNCTION;
368 virtual ~InstLoad() {}
369 };
370
371 // Phi instruction. For incoming edge I, the node is Labels[I] and
372 // the Phi source operand is getSrc(I).
373 class InstPhi : public Inst {
374 public:
375 static InstPhi *create(Cfg *Func, SizeT MaxSrcs, Variable *Dest) {
376 return new (Func->allocateInst<InstPhi>()) InstPhi(Func, MaxSrcs, Dest);
377 }
378 void addArgument(Operand *Source, CfgNode *Label);
379 virtual void dump(const Cfg *Func) const;
380 static bool classof(const Inst *Inst) { return Inst->getKind() == Phi; }
381
382 private:
383 InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest);
384 InstPhi(const InstPhi &) LLVM_DELETED_FUNCTION;
385 InstPhi &operator=(const InstPhi &) LLVM_DELETED_FUNCTION;
386 virtual void destroy(Cfg *Func) {
387 Func->deallocateArrayOf<CfgNode *>(Labels);
388 Inst::destroy(Func);
389 }
390 virtual ~InstPhi() {}
391
392 // Labels[] duplicates the InEdges[] information in the enclosing
393 // CfgNode, but the Phi instruction is created before InEdges[]
394 // is available, so it's more complicated to share the list.
395 CfgNode **Labels;
396 };
397
398 // Ret instruction. The return value is captured in getSrc(0), but if
399 // there is no return value (void-type function), then
400 // getSrcSize()==0 and hasRetValue()==false.
401 class InstRet : public Inst {
402 public:
403 static InstRet *create(Cfg *Func, Operand *RetValue = NULL) {
404 return new (Func->allocateInst<InstRet>()) InstRet(Func, RetValue);
405 }
406 bool hasRetValue() const { return getSrcSize(); }
407 Operand *getRetValue() const {
408 assert(hasRetValue());
409 return getSrc(0);
410 }
411 virtual NodeList getTerminatorEdges() const { return NodeList(); }
412 virtual void dump(const Cfg *Func) const;
413 static bool classof(const Inst *Inst) { return Inst->getKind() == Ret; }
414
415 private:
416 InstRet(Cfg *Func, Operand *RetValue);
417 InstRet(const InstRet &) LLVM_DELETED_FUNCTION;
418 InstRet &operator=(const InstRet &) LLVM_DELETED_FUNCTION;
419 virtual ~InstRet() {}
420 };
421
422 // Select instruction. The condition, true, and false operands are captured.
423 class InstSelect : public Inst {
424 public:
425 static InstSelect *create(Cfg *Func, Variable *Dest, Operand *Condition,
426 Operand *SourceTrue, Operand *SourceFalse) {
427 return new (Func->allocateInst<InstSelect>())
428 InstSelect(Func, Dest, Condition, SourceTrue, SourceFalse);
429 }
430 Operand *getCondition() const { return getSrc(0); }
431 Operand *getTrueOperand() const { return getSrc(1); }
432 Operand *getFalseOperand() const { return getSrc(2); }
433 virtual void dump(const Cfg *Func) const;
434 static bool classof(const Inst *Inst) { return Inst->getKind() == Select; }
435
436 private:
437 InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, Operand *Source1,
438 Operand *Source2);
439 InstSelect(const InstSelect &) LLVM_DELETED_FUNCTION;
440 InstSelect &operator=(const InstSelect &) LLVM_DELETED_FUNCTION;
441 virtual ~InstSelect() {}
442 };
443
444 // Store instruction. The address operand is captured, along with the
445 // data operand to be stored into the address.
446 class InstStore : public Inst {
447 public:
448 static InstStore *create(Cfg *Func, Operand *Data, Operand *Addr) {
449 return new (Func->allocateInst<InstStore>()) InstStore(Func, Data, Addr);
450 }
451 Operand *getAddr() const { return getSrc(1); }
452 Operand *getData() const { return getSrc(0); }
453 virtual void dump(const Cfg *Func) const;
454 static bool classof(const Inst *Inst) { return Inst->getKind() == Store; }
455
456 private:
457 InstStore(Cfg *Func, Operand *Data, Operand *Addr);
458 InstStore(const InstStore &) LLVM_DELETED_FUNCTION;
459 InstStore &operator=(const InstStore &) LLVM_DELETED_FUNCTION;
460 virtual ~InstStore() {}
461 };
462
463 // Switch instruction. The single source operand is captured as
464 // getSrc(0).
465 class InstSwitch : public Inst {
466 public:
467 static InstSwitch *create(Cfg *Func, SizeT NumCases, Operand *Source,
468 CfgNode *LabelDefault) {
469 return new (Func->allocateInst<InstSwitch>())
470 InstSwitch(Func, NumCases, Source, LabelDefault);
471 }
472 Operand *getComparison() const { return getSrc(0); }
473 CfgNode *getLabelDefault() const { return LabelDefault; }
474 SizeT getNumCases() const { return NumCases; }
475 uint64_t getValue(SizeT I) const {
476 assert(I < NumCases);
477 return Values[I];
478 }
479 CfgNode *getLabel(SizeT I) const {
480 assert(I < NumCases);
481 return Labels[I];
482 }
483 void addBranch(SizeT CaseIndex, uint64_t Value, CfgNode *Label);
484 virtual NodeList getTerminatorEdges() const;
485 virtual void dump(const Cfg *Func) const;
486 static bool classof(const Inst *Inst) { return Inst->getKind() == Switch; }
487
488 private:
489 InstSwitch(Cfg *Func, SizeT NumCases, Operand *Source, CfgNode *LabelDefault);
490 InstSwitch(const InstSwitch &) LLVM_DELETED_FUNCTION;
491 InstSwitch &operator=(const InstSwitch &) LLVM_DELETED_FUNCTION;
492 virtual void destroy(Cfg *Func) {
493 Func->deallocateArrayOf<uint64_t>(Values);
494 Func->deallocateArrayOf<CfgNode *>(Labels);
495 Inst::destroy(Func);
496 }
497 virtual ~InstSwitch() {}
498
499 CfgNode *LabelDefault;
500 SizeT NumCases; // not including the default case
501 uint64_t *Values; // size is NumCases
502 CfgNode **Labels; // size is NumCases
503 };
504
505 // Unreachable instruction. This is a terminator instruction with no
506 // operands.
507 class InstUnreachable : public Inst {
508 public:
509 static InstUnreachable *create(Cfg *Func) {
510 return new (Func->allocateInst<InstUnreachable>()) InstUnreachable(Func);
511 }
512 virtual NodeList getTerminatorEdges() const { return NodeList(); }
513 virtual void dump(const Cfg *Func) const;
514 static bool classof(const Inst *Inst) {
515 return Inst->getKind() == Unreachable;
516 }
517
518 private:
519 InstUnreachable(Cfg *Func);
520 InstUnreachable(const InstUnreachable &) LLVM_DELETED_FUNCTION;
521 InstUnreachable &operator=(const InstUnreachable &) LLVM_DELETED_FUNCTION;
522 virtual ~InstUnreachable() {}
523 };
524
525 } // end of namespace Ice
526
527 #endif // SUBZERO_SRC_ICEINST_H
OLDNEW
« no previous file with comments | « src/IceGlobalContext.cpp ('k') | src/IceInst.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698