OLD | NEW |
---|---|
(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 | |
OLD | NEW |