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

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: Changes for JF's followup Created 6 years, 8 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
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, uint32_t Align,
130 Variable *Dest) {
131 return new (Func->allocateInst<InstAlloca>())
132 InstAlloca(Func, ByteCount, Align, Dest);
133 }
134 uint32_t getAlign() const { return Align; }
JF 2014/04/26 20:20:56 Also rename this and the member variable below to
Jim Stichnoth 2014/04/27 15:04:57 Done.
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 Align, Variable *Dest);
141 InstAlloca(const InstAlloca &) LLVM_DELETED_FUNCTION;
142 InstAlloca &operator=(const InstAlloca &) LLVM_DELETED_FUNCTION;
143 virtual ~InstAlloca() {}
144 const uint32_t Align;
145 };
146
147 // Binary arithmetic instruction. The source operands are captured in
148 // getSrc(0) and getSrc(1).
149 class InstArithmetic : public Inst {
150 public:
151 enum OpKind {
152 #define X(tag, str, commutative) tag,
153 ICEINSTARITHMETIC_TABLE
154 #undef X
155 };
156 static InstArithmetic *create(Cfg *Func, OpKind Op, Variable *Dest,
157 Operand *Source1, Operand *Source2) {
158 return new (Func->allocateInst<InstArithmetic>())
159 InstArithmetic(Func, Op, Dest, Source1, Source2);
160 }
161 OpKind getOp() const { return Op; }
162 bool isCommutative() const;
163 virtual void dump(const Cfg *Func) const;
164 static bool classof(const Inst *Inst) {
165 return Inst->getKind() == Arithmetic;
166 }
167
168 private:
169 InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, Operand *Source1,
170 Operand *Source2);
171 InstArithmetic(const InstArithmetic &) LLVM_DELETED_FUNCTION;
172 InstArithmetic &operator=(const InstArithmetic &) LLVM_DELETED_FUNCTION;
173 virtual ~InstArithmetic() {}
174
175 const OpKind Op;
176 };
177
178 // Assignment instruction. The source operand is captured in
179 // getSrc(0). This is not part of the LLVM bitcode, but is a useful
180 // abstraction for some of the lowering. E.g., if Phi instruction
181 // lowering happens before target lowering, or for representing an
182 // Inttoptr instruction, or as an intermediate step for lowering a
183 // Load instruction.
184 class InstAssign : public Inst {
185 public:
186 static InstAssign *create(Cfg *Func, Variable *Dest, Operand *Source) {
187 return new (Func->allocateInst<InstAssign>())
188 InstAssign(Func, Dest, Source);
189 }
190 virtual void dump(const Cfg *Func) const;
191 static bool classof(const Inst *Inst) { return Inst->getKind() == Assign; }
192
193 private:
194 InstAssign(Cfg *Func, Variable *Dest, Operand *Source);
195 InstAssign(const InstAssign &) LLVM_DELETED_FUNCTION;
196 InstAssign &operator=(const InstAssign &) LLVM_DELETED_FUNCTION;
197 virtual ~InstAssign() {}
198 };
199
200 // Branch instruction. This represents both conditional and
201 // unconditional branches.
202 class InstBr : public Inst {
203 public:
204 // Create a conditional branch. If TargetTrue==TargetFalse, it is
205 // optimized to an unconditional branch.
206 static InstBr *create(Cfg *Func, Operand *Source, CfgNode *TargetTrue,
207 CfgNode *TargetFalse) {
208 return new (Func->allocateInst<InstBr>())
209 InstBr(Func, Source, TargetTrue, TargetFalse);
210 }
211 // Create an unconditional branch.
212 static InstBr *create(Cfg *Func, CfgNode *Target) {
213 return new (Func->allocateInst<InstBr>()) InstBr(Func, Target);
214 }
215 bool isUnconditional() const { return getTargetTrue() == NULL; }
216 Operand *getCondition() const {
217 assert(!isUnconditional());
218 return getSrc(0);
219 }
220 CfgNode *getTargetTrue() const { return TargetTrue; }
221 CfgNode *getTargetFalse() const { return TargetFalse; }
222 CfgNode *getTargetUnconditional() const {
223 assert(isUnconditional());
224 return getTargetFalse();
225 }
226 virtual NodeList getTerminatorEdges() const;
227 virtual void dump(const Cfg *Func) const;
228 static bool classof(const Inst *Inst) { return Inst->getKind() == Br; }
229
230 private:
231 // Conditional branch
232 InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, CfgNode *TargetFalse);
233 // Unconditional branch
234 InstBr(Cfg *Func, CfgNode *Target);
235 InstBr(const InstBr &) LLVM_DELETED_FUNCTION;
236 InstBr &operator=(const InstBr &) LLVM_DELETED_FUNCTION;
237 virtual ~InstBr() {}
238
239 CfgNode *const TargetFalse; // Doubles as unconditional branch target
240 CfgNode *const TargetTrue; // NULL if unconditional branch
241 };
242
243 // Call instruction. The call target is captured as getSrc(0), and
244 // arg I is captured as getSrc(I+1).
245 class InstCall : public Inst {
246 public:
247 static InstCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest,
248 Operand *CallTarget) {
249 return new (Func->allocateInst<InstCall>())
250 InstCall(Func, NumArgs, Dest, CallTarget);
251 }
252 void addArg(Operand *Arg) { addSource(Arg); }
253 Operand *getCallTarget() const { return getSrc(0); }
254 Operand *getArg(SizeT I) const { return getSrc(I + 1); }
255 SizeT getNumArgs() const { return getSrcSize() - 1; }
256 virtual void dump(const Cfg *Func) const;
257 static bool classof(const Inst *Inst) { return Inst->getKind() == Call; }
258
259 private:
260 InstCall(Cfg *Func, SizeT NumArgs, Variable *Dest, Operand *CallTarget)
261 : Inst(Func, Inst::Call, NumArgs + 1, Dest) {
262 // Set HasSideEffects so that the call instruction can't be
263 // dead-code eliminated. Don't set this for a deletable intrinsic
264 // call.
265 HasSideEffects = true;
266 addSource(CallTarget);
267 }
268 InstCall(const InstCall &) LLVM_DELETED_FUNCTION;
269 InstCall &operator=(const InstCall &) LLVM_DELETED_FUNCTION;
270 virtual ~InstCall() {}
271 };
272
273 // Cast instruction (a.k.a. conversion operation).
274 class InstCast : public Inst {
275 public:
276 enum OpKind {
277 #define X(tag, str) tag,
278 ICEINSTCAST_TABLE
279 #undef X
280 };
281 static InstCast *create(Cfg *Func, OpKind CastKind, Variable *Dest,
282 Operand *Source) {
283 return new (Func->allocateInst<InstCast>())
284 InstCast(Func, CastKind, Dest, Source);
285 }
286 OpKind getCastKind() const { return CastKind; }
287 virtual void dump(const Cfg *Func) const;
288 static bool classof(const Inst *Inst) { return Inst->getKind() == Cast; }
289
290 private:
291 InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source);
292 InstCast(const InstCast &) LLVM_DELETED_FUNCTION;
293 InstCast &operator=(const InstCast &) LLVM_DELETED_FUNCTION;
294 virtual ~InstCast() {}
295 const OpKind CastKind;
296 };
297
298 // Floating-point comparison instruction. The source operands are
299 // captured in getSrc(0) and getSrc(1).
300 class InstFcmp : public Inst {
301 public:
302 enum FCond {
303 #define X(tag, str) tag,
304 ICEINSTFCMP_TABLE
305 #undef X
306 };
307 static InstFcmp *create(Cfg *Func, FCond Condition, Variable *Dest,
308 Operand *Source1, Operand *Source2) {
309 return new (Func->allocateInst<InstFcmp>())
310 InstFcmp(Func, Condition, Dest, Source1, Source2);
311 }
312 FCond getCondition() const { return Condition; }
313 virtual void dump(const Cfg *Func) const;
314 static bool classof(const Inst *Inst) { return Inst->getKind() == Fcmp; }
315
316 private:
317 InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1,
318 Operand *Source2);
319 InstFcmp(const InstFcmp &) LLVM_DELETED_FUNCTION;
320 InstFcmp &operator=(const InstFcmp &) LLVM_DELETED_FUNCTION;
321 virtual ~InstFcmp() {}
322 const FCond Condition;
323 };
324
325 // Integer comparison instruction. The source operands are captured
326 // in getSrc(0) and getSrc(1).
327 class InstIcmp : public Inst {
328 public:
329 enum ICond {
330 #define X(tag, str) tag,
331 ICEINSTICMP_TABLE
332 #undef X
333 };
334 static InstIcmp *create(Cfg *Func, ICond Condition, Variable *Dest,
335 Operand *Source1, Operand *Source2) {
336 return new (Func->allocateInst<InstIcmp>())
337 InstIcmp(Func, Condition, Dest, Source1, Source2);
338 }
339 ICond getCondition() const { return Condition; }
340 virtual void dump(const Cfg *Func) const;
341 static bool classof(const Inst *Inst) { return Inst->getKind() == Icmp; }
342
343 private:
344 InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1,
345 Operand *Source2);
346 InstIcmp(const InstIcmp &) LLVM_DELETED_FUNCTION;
347 InstIcmp &operator=(const InstIcmp &) LLVM_DELETED_FUNCTION;
348 virtual ~InstIcmp() {}
349 const ICond Condition;
350 };
351
352 // Load instruction. The source address is captured in getSrc(0).
353 class InstLoad : public Inst {
354 public:
355 static InstLoad *create(Cfg *Func, Variable *Dest, Operand *SourceAddr) {
356 return new (Func->allocateInst<InstLoad>())
357 InstLoad(Func, Dest, SourceAddr);
358 }
359 Operand *getSourceAddress() const { return getSrc(0); }
360 virtual void dump(const Cfg *Func) const;
361 static bool classof(const Inst *Inst) { return Inst->getKind() == Load; }
362
363 private:
364 InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr);
365 InstLoad(const InstLoad &) LLVM_DELETED_FUNCTION;
366 InstLoad &operator=(const InstLoad &) LLVM_DELETED_FUNCTION;
367 virtual ~InstLoad() {}
368 };
369
370 // Phi instruction. For incoming edge I, the node is Labels[I] and
371 // the Phi source operand is getSrc(I).
372 class InstPhi : public Inst {
373 public:
374 static InstPhi *create(Cfg *Func, SizeT MaxSrcs, Variable *Dest) {
375 return new (Func->allocateInst<InstPhi>()) InstPhi(Func, MaxSrcs, Dest);
376 }
377 void addArgument(Operand *Source, CfgNode *Label);
378 virtual void dump(const Cfg *Func) const;
379 static bool classof(const Inst *Inst) { return Inst->getKind() == Phi; }
380
381 private:
382 InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest);
383 InstPhi(const InstPhi &) LLVM_DELETED_FUNCTION;
384 InstPhi &operator=(const InstPhi &) LLVM_DELETED_FUNCTION;
385 virtual void destroy(Cfg *Func) {
386 Func->deallocateArrayOf<CfgNode *>(Labels);
387 Inst::destroy(Func);
388 }
389 virtual ~InstPhi() {}
390
391 // Labels[] duplicates the InEdges[] information in the enclosing
392 // CfgNode, but the Phi instruction is created before InEdges[]
393 // is available, so it's more complicated to share the list.
394 CfgNode **Labels;
395 };
396
397 // Ret instruction. The return value is captured in getSrc(0), but if
398 // there is no return value (void-type function), then
399 // getSrcSize()==0 and hasRetValue()==false.
400 class InstRet : public Inst {
401 public:
402 static InstRet *create(Cfg *Func, Operand *RetValue = NULL) {
403 return new (Func->allocateInst<InstRet>()) InstRet(Func, RetValue);
404 }
405 bool hasRetValue() const { return getSrcSize(); }
406 Operand *getRetValue() const {
407 assert(hasRetValue());
408 return getSrc(0);
409 }
410 virtual NodeList getTerminatorEdges() const { return NodeList(); }
411 virtual void dump(const Cfg *Func) const;
412 static bool classof(const Inst *Inst) { return Inst->getKind() == Ret; }
413
414 private:
415 InstRet(Cfg *Func, Operand *RetValue);
416 InstRet(const InstRet &) LLVM_DELETED_FUNCTION;
417 InstRet &operator=(const InstRet &) LLVM_DELETED_FUNCTION;
418 virtual ~InstRet() {}
419 };
420
421 // Select instruction. The condition, true, and false operands are captured.
422 class InstSelect : public Inst {
423 public:
424 static InstSelect *create(Cfg *Func, Variable *Dest, Operand *Condition,
425 Operand *SourceTrue, Operand *SourceFalse) {
426 return new (Func->allocateInst<InstSelect>())
427 InstSelect(Func, Dest, Condition, SourceTrue, SourceFalse);
428 }
429 Operand *getCondition() const { return getSrc(0); }
430 Operand *getTrueOperand() const { return getSrc(1); }
431 Operand *getFalseOperand() const { return getSrc(2); }
432 virtual void dump(const Cfg *Func) const;
433 static bool classof(const Inst *Inst) { return Inst->getKind() == Select; }
434
435 private:
436 InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, Operand *Source1,
437 Operand *Source2);
438 InstSelect(const InstSelect &) LLVM_DELETED_FUNCTION;
439 InstSelect &operator=(const InstSelect &) LLVM_DELETED_FUNCTION;
440 virtual ~InstSelect() {}
441 };
442
443 // Store instruction. The address operand is captured, along with the
444 // data operand to be stored into the address.
445 class InstStore : public Inst {
446 public:
447 static InstStore *create(Cfg *Func, Operand *Data, Operand *Addr) {
448 return new (Func->allocateInst<InstStore>()) InstStore(Func, Data, Addr);
449 }
450 Operand *getAddr() const { return getSrc(1); }
451 Operand *getData() const { return getSrc(0); }
452 virtual void dump(const Cfg *Func) const;
453 static bool classof(const Inst *Inst) { return Inst->getKind() == Store; }
454
455 private:
456 InstStore(Cfg *Func, Operand *Data, Operand *Addr);
457 InstStore(const InstStore &) LLVM_DELETED_FUNCTION;
458 InstStore &operator=(const InstStore &) LLVM_DELETED_FUNCTION;
459 virtual ~InstStore() {}
460 };
461
462 // Switch instruction. The single source operand is captured as
463 // getSrc(0).
464 class InstSwitch : public Inst {
465 public:
466 static InstSwitch *create(Cfg *Func, SizeT NumCases, Operand *Source,
467 CfgNode *LabelDefault) {
468 return new (Func->allocateInst<InstSwitch>())
469 InstSwitch(Func, NumCases, Source, LabelDefault);
470 }
471 Operand *getComparison() const { return getSrc(0); }
472 CfgNode *getLabelDefault() const { return LabelDefault; }
473 SizeT getNumCases() const { return NumCases; }
474 uint64_t getValue(SizeT I) const {
475 assert(I < NumCases);
476 return Values[I];
477 }
478 CfgNode *getLabel(SizeT I) const {
479 assert(I < NumCases);
480 return Labels[I];
481 }
482 void addBranch(SizeT CaseIndex, uint64_t Value, CfgNode *Label);
483 virtual NodeList getTerminatorEdges() const;
484 virtual void dump(const Cfg *Func) const;
485 static bool classof(const Inst *Inst) { return Inst->getKind() == Switch; }
486
487 private:
488 InstSwitch(Cfg *Func, SizeT NumCases, Operand *Source, CfgNode *LabelDefault);
489 InstSwitch(const InstSwitch &) LLVM_DELETED_FUNCTION;
490 InstSwitch &operator=(const InstSwitch &) LLVM_DELETED_FUNCTION;
491 virtual void destroy(Cfg *Func) {
492 Func->deallocateArrayOf<uint64_t>(Values);
493 Func->deallocateArrayOf<CfgNode *>(Labels);
494 Inst::destroy(Func);
495 }
496 virtual ~InstSwitch() {}
497
498 CfgNode *LabelDefault;
499 SizeT NumCases; // not including the default case
500 uint64_t *Values; // size is NumCases
501 CfgNode **Labels; // size is NumCases
502 };
503
504 // Unreachable instruction. This is a terminator instruction with no
505 // operands.
506 class InstUnreachable : public Inst {
507 public:
508 static InstUnreachable *create(Cfg *Func) {
509 return new (Func->allocateInst<InstUnreachable>()) InstUnreachable(Func);
510 }
511 virtual NodeList getTerminatorEdges() const { return NodeList(); }
512 virtual void dump(const Cfg *Func) const;
513 static bool classof(const Inst *Inst) {
514 return Inst->getKind() == Unreachable;
515 }
516
517 private:
518 InstUnreachable(Cfg *Func);
519 InstUnreachable(const InstUnreachable &) LLVM_DELETED_FUNCTION;
520 InstUnreachable &operator=(const InstUnreachable &) LLVM_DELETED_FUNCTION;
521 virtual ~InstUnreachable() {}
522 };
523
524 } // end of namespace Ice
525
526 #endif // SUBZERO_SRC_ICEINST_H
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698