OLD | NEW |
1 //===- subzero/src/IceInst.h - High-level instructions ----------*- C++ -*-===// | 1 //===- subzero/src/IceInst.h - High-level instructions ----------*- C++ -*-===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
11 /// This file declares the Inst class and its target-independent | 11 /// This file declares the Inst class and its target-independent |
12 /// subclasses, which represent the high-level Vanilla ICE instructions | 12 /// subclasses, which represent the high-level Vanilla ICE instructions |
13 /// and map roughly 1:1 to LLVM instructions. | 13 /// and map roughly 1:1 to LLVM instructions. |
14 /// | 14 /// |
15 //===----------------------------------------------------------------------===// | 15 //===----------------------------------------------------------------------===// |
16 | 16 |
17 #ifndef SUBZERO_SRC_ICEINST_H | 17 #ifndef SUBZERO_SRC_ICEINST_H |
18 #define SUBZERO_SRC_ICEINST_H | 18 #define SUBZERO_SRC_ICEINST_H |
19 | 19 |
20 #include "IceCfg.h" | 20 #include "IceCfg.h" |
21 #include "IceDefs.h" | 21 #include "IceDefs.h" |
22 #include "IceInst.def" | 22 #include "IceInst.def" |
23 #include "IceIntrinsics.h" | 23 #include "IceIntrinsics.h" |
24 #include "IceTypes.h" | 24 #include "IceTypes.h" |
25 | 25 |
26 // TODO: The Cfg structure, and instructions in particular, need to be | 26 // TODO: The Cfg structure, and instructions in particular, need to be |
27 // validated for things like valid operand types, valid branch targets, proper | 27 // validated for things like valid operand types, valid branch targets, proper |
28 // ordering of Phi and non-Phi instructions, etc. Most of the validity | 28 // ordering of Phi and non-Phi instructions, etc. Most of the validity checking |
29 // checking will be done in the bitcode reader. We need a list of everything | 29 // will be done in the bitcode reader. We need a list of everything that should |
30 // that should be validated, and tests for each. | 30 // be validated, and tests for each. |
31 | 31 |
32 namespace Ice { | 32 namespace Ice { |
33 | 33 |
34 /// Base instruction class for ICE. Inst has two subclasses: InstHighLevel and | 34 /// Base instruction class for ICE. Inst has two subclasses: InstHighLevel and |
35 /// InstTarget. High-level ICE instructions inherit from InstHighLevel, and | 35 /// InstTarget. High-level ICE instructions inherit from InstHighLevel, and |
36 /// low-level (target-specific) ICE instructions inherit from InstTarget. | 36 /// low-level (target-specific) ICE instructions inherit from InstTarget. |
37 class Inst : public llvm::ilist_node<Inst> { | 37 class Inst : public llvm::ilist_node<Inst> { |
38 Inst() = delete; | 38 Inst() = delete; |
39 Inst(const Inst &) = delete; | 39 Inst(const Inst &) = delete; |
40 Inst &operator=(const Inst &) = delete; | 40 Inst &operator=(const Inst &) = delete; |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 /// duplicates. | 111 /// duplicates. |
112 virtual NodeList getTerminatorEdges() const { | 112 virtual NodeList getTerminatorEdges() const { |
113 // All valid terminator instructions override this method. For the default | 113 // All valid terminator instructions override this method. For the default |
114 // implementation, we assert in case some CfgNode is constructed without a | 114 // implementation, we assert in case some CfgNode is constructed without a |
115 // terminator instruction at the end. | 115 // terminator instruction at the end. |
116 llvm_unreachable( | 116 llvm_unreachable( |
117 "getTerminatorEdges() called on a non-terminator instruction"); | 117 "getTerminatorEdges() called on a non-terminator instruction"); |
118 return NodeList(); | 118 return NodeList(); |
119 } | 119 } |
120 virtual bool isUnconditionalBranch() const { return false; } | 120 virtual bool isUnconditionalBranch() const { return false; } |
121 /// If the instruction is a branch-type instruction with OldNode as a | 121 /// If the instruction is a branch-type instruction with OldNode as a target, |
122 /// target, repoint it to NewNode and return true, otherwise return | 122 /// repoint it to NewNode and return true, otherwise return false. Repoint all |
123 /// false. Repoint all instances of OldNode as a target. | 123 /// instances of OldNode as a target. |
124 virtual bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) { | 124 virtual bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) { |
125 (void)OldNode; | 125 (void)OldNode; |
126 (void)NewNode; | 126 (void)NewNode; |
127 return false; | 127 return false; |
128 } | 128 } |
129 | 129 |
130 virtual bool isSimpleAssign() const { return false; } | 130 virtual bool isSimpleAssign() const { return false; } |
131 | 131 |
132 void livenessLightweight(Cfg *Func, LivenessBV &Live); | 132 void livenessLightweight(Cfg *Func, LivenessBV &Live); |
133 // Calculates liveness for this instruction. Returns true if this | 133 /// Calculates liveness for this instruction. Returns true if this instruction |
134 /// instruction is (tentatively) still live and should be retained, and false | 134 /// is (tentatively) still live and should be retained, and false if this |
135 /// if this instruction is (tentatively) dead and should be deleted. The | 135 /// instruction is (tentatively) dead and should be deleted. The decision is |
136 /// decision is tentative until the liveness dataflow algorithm has converged, | 136 /// tentative until the liveness dataflow algorithm has converged, and then a |
137 /// and then a separate pass permanently deletes dead instructions. | 137 /// separate pass permanently deletes dead instructions. |
138 bool liveness(InstNumberT InstNumber, LivenessBV &Live, Liveness *Liveness, | 138 bool liveness(InstNumberT InstNumber, LivenessBV &Live, Liveness *Liveness, |
139 LiveBeginEndMap *LiveBegin, LiveBeginEndMap *LiveEnd); | 139 LiveBeginEndMap *LiveBegin, LiveBeginEndMap *LiveEnd); |
140 | 140 |
141 /// Get the number of native instructions that this instruction ultimately | 141 /// Get the number of native instructions that this instruction ultimately |
142 /// emits. By default, high-level instructions don't result in any native | 142 /// emits. By default, high-level instructions don't result in any native |
143 /// instructions, and a target-specific instruction results in a single native | 143 /// instructions, and a target-specific instruction results in a single native |
144 /// instruction. | 144 /// instruction. |
145 virtual uint32_t getEmitInstCount() const { return 0; } | 145 virtual uint32_t getEmitInstCount() const { return 0; } |
146 // TODO(stichnot): Change Inst back to abstract once the g++ build | 146 // TODO(stichnot): Change Inst back to abstract once the g++ build issue is |
147 // issue is fixed. llvm::ilist<Ice::Inst> doesn't work under g++ | 147 // fixed. llvm::ilist<Ice::Inst> doesn't work under g++ because the |
148 // because the resize(size_t, Ice::Inst) method is incorrectly | 148 // resize(size_t, Ice::Inst) method is incorrectly declared and thus doesn't |
149 // declared and thus doesn't allow the abstract class Ice::Inst. | 149 // allow the abstract class Ice::Inst. The method should be declared |
150 // The method should be declared resize(size_t, const Ice::Inst &). | 150 // resize(size_t, const Ice::Inst &). virtual void emit(const Cfg *Func) |
151 // virtual void emit(const Cfg *Func) const = 0; | 151 // const = 0; virtual void emitIAS(const Cfg *Func) const = 0; |
152 // virtual void emitIAS(const Cfg *Func) const = 0; | |
153 virtual void emit(const Cfg *) const { | 152 virtual void emit(const Cfg *) const { |
154 llvm_unreachable("emit on abstract class"); | 153 llvm_unreachable("emit on abstract class"); |
155 } | 154 } |
156 virtual void emitIAS(const Cfg *Func) const { emit(Func); } | 155 virtual void emitIAS(const Cfg *Func) const { emit(Func); } |
157 virtual void dump(const Cfg *Func) const; | 156 virtual void dump(const Cfg *Func) const; |
158 virtual void dumpExtras(const Cfg *Func) const; | 157 virtual void dumpExtras(const Cfg *Func) const; |
159 void dumpDecorated(const Cfg *Func) const; | 158 void dumpDecorated(const Cfg *Func) const; |
160 void emitSources(const Cfg *Func) const; | 159 void emitSources(const Cfg *Func) const; |
161 void dumpSources(const Cfg *Func) const; | 160 void dumpSources(const Cfg *Func) const; |
162 void dumpDest(const Cfg *Func) const; | 161 void dumpDest(const Cfg *Func) const; |
163 virtual bool isRedundantAssign() const { return false; } | 162 virtual bool isRedundantAssign() const { return false; } |
164 | 163 |
165 // TODO(jpp): Insts should not have non-trivial destructors, but they | 164 // TODO(jpp): Insts should not have non-trivial destructors, but they |
166 // currently do. This dtor is marked final as a multi-step refactor that | 165 // currently do. This dtor is marked final as a multi-step refactor that |
167 // will eventually fix this problem. | 166 // will eventually fix this problem. |
168 virtual ~Inst() = default; | 167 virtual ~Inst() = default; |
169 | 168 |
170 protected: | 169 protected: |
171 Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest); | 170 Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest); |
172 void addSource(Operand *Src) { | 171 void addSource(Operand *Src) { |
173 assert(Src); | 172 assert(Src); |
174 assert(NumSrcs < MaxSrcs); | 173 assert(NumSrcs < MaxSrcs); |
175 Srcs[NumSrcs++] = Src; | 174 Srcs[NumSrcs++] = Src; |
176 } | 175 } |
177 void setLastUse(SizeT VarIndex) { | 176 void setLastUse(SizeT VarIndex) { |
178 if (VarIndex < CHAR_BIT * sizeof(LiveRangesEnded)) | 177 if (VarIndex < CHAR_BIT * sizeof(LiveRangesEnded)) |
179 LiveRangesEnded |= (((LREndedBits)1u) << VarIndex); | 178 LiveRangesEnded |= (((LREndedBits)1u) << VarIndex); |
180 } | 179 } |
181 void resetLastUses() { LiveRangesEnded = 0; } | 180 void resetLastUses() { LiveRangesEnded = 0; } |
182 /// The destroy() method lets the instruction cleanly release any | 181 /// The destroy() method lets the instruction cleanly release any memory that |
183 /// memory that was allocated via the Cfg's allocator. | 182 /// was allocated via the Cfg's allocator. |
184 virtual void destroy(Cfg *Func) { Func->deallocateArrayOf<Operand *>(Srcs); } | 183 virtual void destroy(Cfg *Func) { Func->deallocateArrayOf<Operand *>(Srcs); } |
185 | 184 |
186 const InstKind Kind; | 185 const InstKind Kind; |
187 /// Number is the instruction number for describing live ranges. | 186 /// Number is the instruction number for describing live ranges. |
188 InstNumberT Number; | 187 InstNumberT Number; |
189 /// Deleted means irrevocably deleted. | 188 /// Deleted means irrevocably deleted. |
190 bool Deleted = false; | 189 bool Deleted = false; |
191 /// Dead means one of two things depending on context: (1) pending | 190 /// Dead means one of two things depending on context: (1) pending deletion |
192 /// deletion after liveness analysis converges, or (2) marked for | 191 /// after liveness analysis converges, or (2) marked for deletion during |
193 /// deletion during lowering due to a folded bool operation. | 192 /// lowering due to a folded bool operation. |
194 bool Dead = false; | 193 bool Dead = false; |
195 /// HasSideEffects means the instruction is something like a function | 194 /// HasSideEffects means the instruction is something like a function call or |
196 /// call or a volatile load that can't be removed even if its Dest | 195 /// a volatile load that can't be removed even if its Dest variable is not |
197 /// variable is not live. | 196 /// live. |
198 bool HasSideEffects = false; | 197 bool HasSideEffects = false; |
199 /// IsDestNonKillable means that liveness analysis shouldn't consider | 198 /// IsDestNonKillable means that liveness analysis shouldn't consider this |
200 /// this instruction to kill the Dest variable. This is used when | 199 /// instruction to kill the Dest variable. This is used when lowering produces |
201 /// lowering produces two assignments to the same variable. | 200 /// two assignments to the same variable. |
202 bool IsDestNonKillable = false; | 201 bool IsDestNonKillable = false; |
203 | 202 |
204 Variable *Dest; | 203 Variable *Dest; |
205 const SizeT MaxSrcs; // only used for assert | 204 const SizeT MaxSrcs; // only used for assert |
206 SizeT NumSrcs = 0; | 205 SizeT NumSrcs = 0; |
207 Operand **Srcs; | 206 Operand **Srcs; |
208 | 207 |
209 /// LiveRangesEnded marks which Variables' live ranges end in this | 208 /// LiveRangesEnded marks which Variables' live ranges end in this |
210 /// instruction. An instruction can have an arbitrary number of | 209 /// instruction. An instruction can have an arbitrary number of source |
211 /// source operands (e.g. a call instruction), and each source | 210 /// operands (e.g. a call instruction), and each source operand can contain 0 |
212 /// operand can contain 0 or 1 Variable (and target-specific operands | 211 /// or 1 Variable (and target-specific operands could contain more than 1 |
213 /// could contain more than 1 Variable). All the variables in an | 212 /// Variable). All the variables in an instruction are conceptually flattened |
214 /// instruction are conceptually flattened and each variable is | 213 /// and each variable is mapped to one bit position of the LiveRangesEnded bit |
215 /// mapped to one bit position of the LiveRangesEnded bit vector. | 214 /// vector. Only the first CHAR_BIT * sizeof(LREndedBits) variables are |
216 /// Only the first CHAR_BIT * sizeof(LREndedBits) variables are | |
217 /// tracked this way. | 215 /// tracked this way. |
218 using LREndedBits = uint32_t; // only first 32 src operands tracked, sorry | 216 using LREndedBits = uint32_t; // only first 32 src operands tracked, sorry |
219 LREndedBits LiveRangesEnded; | 217 LREndedBits LiveRangesEnded; |
220 }; | 218 }; |
221 | 219 |
222 class InstHighLevel : public Inst { | 220 class InstHighLevel : public Inst { |
223 InstHighLevel() = delete; | 221 InstHighLevel() = delete; |
224 InstHighLevel(const InstHighLevel &) = delete; | 222 InstHighLevel(const InstHighLevel &) = delete; |
225 InstHighLevel &operator=(const InstHighLevel &) = delete; | 223 InstHighLevel &operator=(const InstHighLevel &) = delete; |
226 | 224 |
227 protected: | 225 protected: |
228 InstHighLevel(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) | 226 InstHighLevel(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) |
229 : Inst(Func, Kind, MaxSrcs, Dest) {} | 227 : Inst(Func, Kind, MaxSrcs, Dest) {} |
230 void emit(const Cfg * /*Func*/) const override { | 228 void emit(const Cfg * /*Func*/) const override { |
231 llvm_unreachable("emit() called on a non-lowered instruction"); | 229 llvm_unreachable("emit() called on a non-lowered instruction"); |
232 } | 230 } |
233 void emitIAS(const Cfg * /*Func*/) const override { | 231 void emitIAS(const Cfg * /*Func*/) const override { |
234 llvm_unreachable("emitIAS() called on a non-lowered instruction"); | 232 llvm_unreachable("emitIAS() called on a non-lowered instruction"); |
235 } | 233 } |
236 }; | 234 }; |
237 | 235 |
238 /// Alloca instruction. This captures the size in bytes as getSrc(0), | 236 /// Alloca instruction. This captures the size in bytes as getSrc(0), and the |
239 /// and the required alignment in bytes. The alignment must be either | 237 /// required alignment in bytes. The alignment must be either 0 (no alignment |
240 /// 0 (no alignment required) or a power of 2. | 238 /// required) or a power of 2. |
241 class InstAlloca : public InstHighLevel { | 239 class InstAlloca : public InstHighLevel { |
242 InstAlloca() = delete; | 240 InstAlloca() = delete; |
243 InstAlloca(const InstAlloca &) = delete; | 241 InstAlloca(const InstAlloca &) = delete; |
244 InstAlloca &operator=(const InstAlloca &) = delete; | 242 InstAlloca &operator=(const InstAlloca &) = delete; |
245 | 243 |
246 public: | 244 public: |
247 static InstAlloca *create(Cfg *Func, Operand *ByteCount, | 245 static InstAlloca *create(Cfg *Func, Operand *ByteCount, |
248 uint32_t AlignInBytes, Variable *Dest) { | 246 uint32_t AlignInBytes, Variable *Dest) { |
249 return new (Func->allocate<InstAlloca>()) | 247 return new (Func->allocate<InstAlloca>()) |
250 InstAlloca(Func, ByteCount, AlignInBytes, Dest); | 248 InstAlloca(Func, ByteCount, AlignInBytes, Dest); |
251 } | 249 } |
252 uint32_t getAlignInBytes() const { return AlignInBytes; } | 250 uint32_t getAlignInBytes() const { return AlignInBytes; } |
253 Operand *getSizeInBytes() const { return getSrc(0); } | 251 Operand *getSizeInBytes() const { return getSrc(0); } |
254 void dump(const Cfg *Func) const override; | 252 void dump(const Cfg *Func) const override; |
255 static bool classof(const Inst *Inst) { return Inst->getKind() == Alloca; } | 253 static bool classof(const Inst *Inst) { return Inst->getKind() == Alloca; } |
256 | 254 |
257 private: | 255 private: |
258 InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, | 256 InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, |
259 Variable *Dest); | 257 Variable *Dest); |
260 | 258 |
261 const uint32_t AlignInBytes; | 259 const uint32_t AlignInBytes; |
262 }; | 260 }; |
263 | 261 |
264 /// Binary arithmetic instruction. The source operands are captured in | 262 /// Binary arithmetic instruction. The source operands are captured in getSrc(0) |
265 /// getSrc(0) and getSrc(1). | 263 /// and getSrc(1). |
266 class InstArithmetic : public InstHighLevel { | 264 class InstArithmetic : public InstHighLevel { |
267 InstArithmetic() = delete; | 265 InstArithmetic() = delete; |
268 InstArithmetic(const InstArithmetic &) = delete; | 266 InstArithmetic(const InstArithmetic &) = delete; |
269 InstArithmetic &operator=(const InstArithmetic &) = delete; | 267 InstArithmetic &operator=(const InstArithmetic &) = delete; |
270 | 268 |
271 public: | 269 public: |
272 enum OpKind { | 270 enum OpKind { |
273 #define X(tag, str, commutative) tag, | 271 #define X(tag, str, commutative) tag, |
274 ICEINSTARITHMETIC_TABLE | 272 ICEINSTARITHMETIC_TABLE |
275 #undef X | 273 #undef X |
(...skipping 13 matching lines...) Expand all Loading... |
289 return Inst->getKind() == Arithmetic; | 287 return Inst->getKind() == Arithmetic; |
290 } | 288 } |
291 | 289 |
292 private: | 290 private: |
293 InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, Operand *Source1, | 291 InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, Operand *Source1, |
294 Operand *Source2); | 292 Operand *Source2); |
295 | 293 |
296 const OpKind Op; | 294 const OpKind Op; |
297 }; | 295 }; |
298 | 296 |
299 /// Assignment instruction. The source operand is captured in | 297 /// Assignment instruction. The source operand is captured in getSrc(0). This is |
300 /// getSrc(0). This is not part of the LLVM bitcode, but is a useful | 298 /// not part of the LLVM bitcode, but is a useful abstraction for some of the |
301 /// abstraction for some of the lowering. E.g., if Phi instruction | 299 /// lowering. E.g., if Phi instruction lowering happens before target lowering, |
302 /// lowering happens before target lowering, or for representing an | 300 /// or for representing an Inttoptr instruction, or as an intermediate step for |
303 /// Inttoptr instruction, or as an intermediate step for lowering a | 301 /// lowering a Load instruction. |
304 /// Load instruction. | |
305 class InstAssign : public InstHighLevel { | 302 class InstAssign : public InstHighLevel { |
306 InstAssign() = delete; | 303 InstAssign() = delete; |
307 InstAssign(const InstAssign &) = delete; | 304 InstAssign(const InstAssign &) = delete; |
308 InstAssign &operator=(const InstAssign &) = delete; | 305 InstAssign &operator=(const InstAssign &) = delete; |
309 | 306 |
310 public: | 307 public: |
311 static InstAssign *create(Cfg *Func, Variable *Dest, Operand *Source) { | 308 static InstAssign *create(Cfg *Func, Variable *Dest, Operand *Source) { |
312 return new (Func->allocate<InstAssign>()) InstAssign(Func, Dest, Source); | 309 return new (Func->allocate<InstAssign>()) InstAssign(Func, Dest, Source); |
313 } | 310 } |
314 bool isSimpleAssign() const override { return true; } | 311 bool isSimpleAssign() const override { return true; } |
315 void dump(const Cfg *Func) const override; | 312 void dump(const Cfg *Func) const override; |
316 static bool classof(const Inst *Inst) { return Inst->getKind() == Assign; } | 313 static bool classof(const Inst *Inst) { return Inst->getKind() == Assign; } |
317 | 314 |
318 private: | 315 private: |
319 InstAssign(Cfg *Func, Variable *Dest, Operand *Source); | 316 InstAssign(Cfg *Func, Variable *Dest, Operand *Source); |
320 }; | 317 }; |
321 | 318 |
322 /// Branch instruction. This represents both conditional and | 319 /// Branch instruction. This represents both conditional and unconditional |
323 /// unconditional branches. | 320 /// branches. |
324 class InstBr : public InstHighLevel { | 321 class InstBr : public InstHighLevel { |
325 InstBr() = delete; | 322 InstBr() = delete; |
326 InstBr(const InstBr &) = delete; | 323 InstBr(const InstBr &) = delete; |
327 InstBr &operator=(const InstBr &) = delete; | 324 InstBr &operator=(const InstBr &) = delete; |
328 | 325 |
329 public: | 326 public: |
330 /// Create a conditional branch. If TargetTrue==TargetFalse, it is | 327 /// Create a conditional branch. If TargetTrue==TargetFalse, it is optimized |
331 /// optimized to an unconditional branch. | 328 /// to an unconditional branch. |
332 static InstBr *create(Cfg *Func, Operand *Source, CfgNode *TargetTrue, | 329 static InstBr *create(Cfg *Func, Operand *Source, CfgNode *TargetTrue, |
333 CfgNode *TargetFalse) { | 330 CfgNode *TargetFalse) { |
334 return new (Func->allocate<InstBr>()) | 331 return new (Func->allocate<InstBr>()) |
335 InstBr(Func, Source, TargetTrue, TargetFalse); | 332 InstBr(Func, Source, TargetTrue, TargetFalse); |
336 } | 333 } |
337 /// Create an unconditional branch. | 334 /// Create an unconditional branch. |
338 static InstBr *create(Cfg *Func, CfgNode *Target) { | 335 static InstBr *create(Cfg *Func, CfgNode *Target) { |
339 return new (Func->allocate<InstBr>()) InstBr(Func, Target); | 336 return new (Func->allocate<InstBr>()) InstBr(Func, Target); |
340 } | 337 } |
341 bool isUnconditional() const { return getTargetTrue() == nullptr; } | 338 bool isUnconditional() const { return getTargetTrue() == nullptr; } |
(...skipping 16 matching lines...) Expand all Loading... |
358 private: | 355 private: |
359 /// Conditional branch | 356 /// Conditional branch |
360 InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, CfgNode *TargetFalse); | 357 InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, CfgNode *TargetFalse); |
361 /// Unconditional branch | 358 /// Unconditional branch |
362 InstBr(Cfg *Func, CfgNode *Target); | 359 InstBr(Cfg *Func, CfgNode *Target); |
363 | 360 |
364 CfgNode *TargetFalse; /// Doubles as unconditional branch target | 361 CfgNode *TargetFalse; /// Doubles as unconditional branch target |
365 CfgNode *TargetTrue; /// nullptr if unconditional branch | 362 CfgNode *TargetTrue; /// nullptr if unconditional branch |
366 }; | 363 }; |
367 | 364 |
368 /// Call instruction. The call target is captured as getSrc(0), and | 365 /// Call instruction. The call target is captured as getSrc(0), and arg I is |
369 /// arg I is captured as getSrc(I+1). | 366 /// captured as getSrc(I+1). |
370 class InstCall : public InstHighLevel { | 367 class InstCall : public InstHighLevel { |
371 InstCall() = delete; | 368 InstCall() = delete; |
372 InstCall(const InstCall &) = delete; | 369 InstCall(const InstCall &) = delete; |
373 InstCall &operator=(const InstCall &) = delete; | 370 InstCall &operator=(const InstCall &) = delete; |
374 | 371 |
375 public: | 372 public: |
376 static InstCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest, | 373 static InstCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest, |
377 Operand *CallTarget, bool HasTailCall) { | 374 Operand *CallTarget, bool HasTailCall) { |
378 /// Set HasSideEffects to true so that the call instruction can't be | 375 /// Set HasSideEffects to true so that the call instruction can't be |
379 /// dead-code eliminated. IntrinsicCalls can override this if the | 376 /// dead-code eliminated. IntrinsicCalls can override this if the particular |
380 /// particular intrinsic is deletable and has no side-effects. | 377 /// intrinsic is deletable and has no side-effects. |
381 const bool HasSideEffects = true; | 378 const bool HasSideEffects = true; |
382 const InstKind Kind = Inst::Call; | 379 const InstKind Kind = Inst::Call; |
383 return new (Func->allocate<InstCall>()) InstCall( | 380 return new (Func->allocate<InstCall>()) InstCall( |
384 Func, NumArgs, Dest, CallTarget, HasTailCall, HasSideEffects, Kind); | 381 Func, NumArgs, Dest, CallTarget, HasTailCall, HasSideEffects, Kind); |
385 } | 382 } |
386 void addArg(Operand *Arg) { addSource(Arg); } | 383 void addArg(Operand *Arg) { addSource(Arg); } |
387 Operand *getCallTarget() const { return getSrc(0); } | 384 Operand *getCallTarget() const { return getSrc(0); } |
388 Operand *getArg(SizeT I) const { return getSrc(I + 1); } | 385 Operand *getArg(SizeT I) const { return getSrc(I + 1); } |
389 SizeT getNumArgs() const { return getSrcSize() - 1; } | 386 SizeT getNumArgs() const { return getSrcSize() - 1; } |
390 bool isTailcall() const { return HasTailCall; } | 387 bool isTailcall() const { return HasTailCall; } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
451 void dump(const Cfg *Func) const override; | 448 void dump(const Cfg *Func) const override; |
452 static bool classof(const Inst *Inst) { | 449 static bool classof(const Inst *Inst) { |
453 return Inst->getKind() == ExtractElement; | 450 return Inst->getKind() == ExtractElement; |
454 } | 451 } |
455 | 452 |
456 private: | 453 private: |
457 InstExtractElement(Cfg *Func, Variable *Dest, Operand *Source1, | 454 InstExtractElement(Cfg *Func, Variable *Dest, Operand *Source1, |
458 Operand *Source2); | 455 Operand *Source2); |
459 }; | 456 }; |
460 | 457 |
461 /// Floating-point comparison instruction. The source operands are | 458 /// Floating-point comparison instruction. The source operands are captured in |
462 /// captured in getSrc(0) and getSrc(1). | 459 /// getSrc(0) and getSrc(1). |
463 class InstFcmp : public InstHighLevel { | 460 class InstFcmp : public InstHighLevel { |
464 InstFcmp() = delete; | 461 InstFcmp() = delete; |
465 InstFcmp(const InstFcmp &) = delete; | 462 InstFcmp(const InstFcmp &) = delete; |
466 InstFcmp &operator=(const InstFcmp &) = delete; | 463 InstFcmp &operator=(const InstFcmp &) = delete; |
467 | 464 |
468 public: | 465 public: |
469 enum FCond { | 466 enum FCond { |
470 #define X(tag, str) tag, | 467 #define X(tag, str) tag, |
471 ICEINSTFCMP_TABLE | 468 ICEINSTFCMP_TABLE |
472 #undef X | 469 #undef X |
473 _num | 470 _num |
474 }; | 471 }; |
475 | 472 |
476 static InstFcmp *create(Cfg *Func, FCond Condition, Variable *Dest, | 473 static InstFcmp *create(Cfg *Func, FCond Condition, Variable *Dest, |
477 Operand *Source1, Operand *Source2) { | 474 Operand *Source1, Operand *Source2) { |
478 return new (Func->allocate<InstFcmp>()) | 475 return new (Func->allocate<InstFcmp>()) |
479 InstFcmp(Func, Condition, Dest, Source1, Source2); | 476 InstFcmp(Func, Condition, Dest, Source1, Source2); |
480 } | 477 } |
481 FCond getCondition() const { return Condition; } | 478 FCond getCondition() const { return Condition; } |
482 void dump(const Cfg *Func) const override; | 479 void dump(const Cfg *Func) const override; |
483 static bool classof(const Inst *Inst) { return Inst->getKind() == Fcmp; } | 480 static bool classof(const Inst *Inst) { return Inst->getKind() == Fcmp; } |
484 | 481 |
485 private: | 482 private: |
486 InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1, | 483 InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1, |
487 Operand *Source2); | 484 Operand *Source2); |
488 | 485 |
489 const FCond Condition; | 486 const FCond Condition; |
490 }; | 487 }; |
491 | 488 |
492 /// Integer comparison instruction. The source operands are captured | 489 /// Integer comparison instruction. The source operands are captured in |
493 /// in getSrc(0) and getSrc(1). | 490 /// getSrc(0) and getSrc(1). |
494 class InstIcmp : public InstHighLevel { | 491 class InstIcmp : public InstHighLevel { |
495 InstIcmp() = delete; | 492 InstIcmp() = delete; |
496 InstIcmp(const InstIcmp &) = delete; | 493 InstIcmp(const InstIcmp &) = delete; |
497 InstIcmp &operator=(const InstIcmp &) = delete; | 494 InstIcmp &operator=(const InstIcmp &) = delete; |
498 | 495 |
499 public: | 496 public: |
500 enum ICond { | 497 enum ICond { |
501 #define X(tag, str) tag, | 498 #define X(tag, str) tag, |
502 ICEINSTICMP_TABLE | 499 ICEINSTICMP_TABLE |
503 #undef X | 500 #undef X |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
536 void dump(const Cfg *Func) const override; | 533 void dump(const Cfg *Func) const override; |
537 static bool classof(const Inst *Inst) { | 534 static bool classof(const Inst *Inst) { |
538 return Inst->getKind() == InsertElement; | 535 return Inst->getKind() == InsertElement; |
539 } | 536 } |
540 | 537 |
541 private: | 538 private: |
542 InstInsertElement(Cfg *Func, Variable *Dest, Operand *Source1, | 539 InstInsertElement(Cfg *Func, Variable *Dest, Operand *Source1, |
543 Operand *Source2, Operand *Source3); | 540 Operand *Source2, Operand *Source3); |
544 }; | 541 }; |
545 | 542 |
546 /// Call to an intrinsic function. The call target is captured as getSrc(0), | 543 /// Call to an intrinsic function. The call target is captured as getSrc(0), and |
547 /// and arg I is captured as getSrc(I+1). | 544 /// arg I is captured as getSrc(I+1). |
548 class InstIntrinsicCall : public InstCall { | 545 class InstIntrinsicCall : public InstCall { |
549 InstIntrinsicCall() = delete; | 546 InstIntrinsicCall() = delete; |
550 InstIntrinsicCall(const InstIntrinsicCall &) = delete; | 547 InstIntrinsicCall(const InstIntrinsicCall &) = delete; |
551 InstIntrinsicCall &operator=(const InstIntrinsicCall &) = delete; | 548 InstIntrinsicCall &operator=(const InstIntrinsicCall &) = delete; |
552 | 549 |
553 public: | 550 public: |
554 static InstIntrinsicCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest, | 551 static InstIntrinsicCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest, |
555 Operand *CallTarget, | 552 Operand *CallTarget, |
556 const Intrinsics::IntrinsicInfo &Info) { | 553 const Intrinsics::IntrinsicInfo &Info) { |
557 return new (Func->allocate<InstIntrinsicCall>()) | 554 return new (Func->allocate<InstIntrinsicCall>()) |
558 InstIntrinsicCall(Func, NumArgs, Dest, CallTarget, Info); | 555 InstIntrinsicCall(Func, NumArgs, Dest, CallTarget, Info); |
559 } | 556 } |
560 static bool classof(const Inst *Inst) { | 557 static bool classof(const Inst *Inst) { |
561 return Inst->getKind() == IntrinsicCall; | 558 return Inst->getKind() == IntrinsicCall; |
562 } | 559 } |
563 | 560 |
564 Intrinsics::IntrinsicInfo getIntrinsicInfo() const { return Info; } | 561 Intrinsics::IntrinsicInfo getIntrinsicInfo() const { return Info; } |
565 | 562 |
566 private: | 563 private: |
567 InstIntrinsicCall(Cfg *Func, SizeT NumArgs, Variable *Dest, | 564 InstIntrinsicCall(Cfg *Func, SizeT NumArgs, Variable *Dest, |
568 Operand *CallTarget, const Intrinsics::IntrinsicInfo &Info) | 565 Operand *CallTarget, const Intrinsics::IntrinsicInfo &Info) |
569 : InstCall(Func, NumArgs, Dest, CallTarget, false, Info.HasSideEffects, | 566 : InstCall(Func, NumArgs, Dest, CallTarget, false, Info.HasSideEffects, |
570 Inst::IntrinsicCall), | 567 Inst::IntrinsicCall), |
571 Info(Info) {} | 568 Info(Info) {} |
572 | 569 |
573 const Intrinsics::IntrinsicInfo Info; | 570 const Intrinsics::IntrinsicInfo Info; |
574 }; | 571 }; |
575 | 572 |
576 /// Load instruction. The source address is captured in getSrc(0). | 573 /// Load instruction. The source address is captured in getSrc(0). |
577 class InstLoad : public InstHighLevel { | 574 class InstLoad : public InstHighLevel { |
578 InstLoad() = delete; | 575 InstLoad() = delete; |
579 InstLoad(const InstLoad &) = delete; | 576 InstLoad(const InstLoad &) = delete; |
580 InstLoad &operator=(const InstLoad &) = delete; | 577 InstLoad &operator=(const InstLoad &) = delete; |
581 | 578 |
582 public: | 579 public: |
583 static InstLoad *create(Cfg *Func, Variable *Dest, Operand *SourceAddr, | 580 static InstLoad *create(Cfg *Func, Variable *Dest, Operand *SourceAddr, |
584 uint32_t Align = 1) { | 581 uint32_t Align = 1) { |
585 // TODO(kschimpf) Stop ignoring alignment specification. | 582 // TODO(kschimpf) Stop ignoring alignment specification. |
586 (void)Align; | 583 (void)Align; |
587 return new (Func->allocate<InstLoad>()) InstLoad(Func, Dest, SourceAddr); | 584 return new (Func->allocate<InstLoad>()) InstLoad(Func, Dest, SourceAddr); |
588 } | 585 } |
589 Operand *getSourceAddress() const { return getSrc(0); } | 586 Operand *getSourceAddress() const { return getSrc(0); } |
590 void dump(const Cfg *Func) const override; | 587 void dump(const Cfg *Func) const override; |
591 static bool classof(const Inst *Inst) { return Inst->getKind() == Load; } | 588 static bool classof(const Inst *Inst) { return Inst->getKind() == Load; } |
592 | 589 |
593 private: | 590 private: |
594 InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr); | 591 InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr); |
595 }; | 592 }; |
596 | 593 |
597 /// Phi instruction. For incoming edge I, the node is Labels[I] and | 594 /// Phi instruction. For incoming edge I, the node is Labels[I] and the Phi |
598 /// the Phi source operand is getSrc(I). | 595 /// source operand is getSrc(I). |
599 class InstPhi : public InstHighLevel { | 596 class InstPhi : public InstHighLevel { |
600 InstPhi() = delete; | 597 InstPhi() = delete; |
601 InstPhi(const InstPhi &) = delete; | 598 InstPhi(const InstPhi &) = delete; |
602 InstPhi &operator=(const InstPhi &) = delete; | 599 InstPhi &operator=(const InstPhi &) = delete; |
603 | 600 |
604 public: | 601 public: |
605 static InstPhi *create(Cfg *Func, SizeT MaxSrcs, Variable *Dest) { | 602 static InstPhi *create(Cfg *Func, SizeT MaxSrcs, Variable *Dest) { |
606 return new (Func->allocate<InstPhi>()) InstPhi(Func, MaxSrcs, Dest); | 603 return new (Func->allocate<InstPhi>()) InstPhi(Func, MaxSrcs, Dest); |
607 } | 604 } |
608 void addArgument(Operand *Source, CfgNode *Label); | 605 void addArgument(Operand *Source, CfgNode *Label); |
609 Operand *getOperandForTarget(CfgNode *Target) const; | 606 Operand *getOperandForTarget(CfgNode *Target) const; |
610 CfgNode *getLabel(SizeT Index) const { return Labels[Index]; } | 607 CfgNode *getLabel(SizeT Index) const { return Labels[Index]; } |
611 void livenessPhiOperand(LivenessBV &Live, CfgNode *Target, | 608 void livenessPhiOperand(LivenessBV &Live, CfgNode *Target, |
612 Liveness *Liveness); | 609 Liveness *Liveness); |
613 Inst *lower(Cfg *Func); | 610 Inst *lower(Cfg *Func); |
614 void dump(const Cfg *Func) const override; | 611 void dump(const Cfg *Func) const override; |
615 static bool classof(const Inst *Inst) { return Inst->getKind() == Phi; } | 612 static bool classof(const Inst *Inst) { return Inst->getKind() == Phi; } |
616 | 613 |
617 private: | 614 private: |
618 InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest); | 615 InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest); |
619 void destroy(Cfg *Func) override { | 616 void destroy(Cfg *Func) override { |
620 Func->deallocateArrayOf<CfgNode *>(Labels); | 617 Func->deallocateArrayOf<CfgNode *>(Labels); |
621 Inst::destroy(Func); | 618 Inst::destroy(Func); |
622 } | 619 } |
623 | 620 |
624 /// Labels[] duplicates the InEdges[] information in the enclosing | 621 /// Labels[] duplicates the InEdges[] information in the enclosing CfgNode, |
625 /// CfgNode, but the Phi instruction is created before InEdges[] | 622 /// but the Phi instruction is created before InEdges[] is available, so it's |
626 /// is available, so it's more complicated to share the list. | 623 /// more complicated to share the list. |
627 CfgNode **Labels; | 624 CfgNode **Labels; |
628 }; | 625 }; |
629 | 626 |
630 /// Ret instruction. The return value is captured in getSrc(0), but if | 627 /// Ret instruction. The return value is captured in getSrc(0), but if there is |
631 /// there is no return value (void-type function), then | 628 /// no return value (void-type function), then getSrcSize()==0 and |
632 /// getSrcSize()==0 and hasRetValue()==false. | 629 /// hasRetValue()==false. |
633 class InstRet : public InstHighLevel { | 630 class InstRet : public InstHighLevel { |
634 InstRet() = delete; | 631 InstRet() = delete; |
635 InstRet(const InstRet &) = delete; | 632 InstRet(const InstRet &) = delete; |
636 InstRet &operator=(const InstRet &) = delete; | 633 InstRet &operator=(const InstRet &) = delete; |
637 | 634 |
638 public: | 635 public: |
639 static InstRet *create(Cfg *Func, Operand *RetValue = nullptr) { | 636 static InstRet *create(Cfg *Func, Operand *RetValue = nullptr) { |
640 return new (Func->allocate<InstRet>()) InstRet(Func, RetValue); | 637 return new (Func->allocate<InstRet>()) InstRet(Func, RetValue); |
641 } | 638 } |
642 bool hasRetValue() const { return getSrcSize(); } | 639 bool hasRetValue() const { return getSrcSize(); } |
(...skipping 25 matching lines...) Expand all Loading... |
668 Operand *getTrueOperand() const { return getSrc(1); } | 665 Operand *getTrueOperand() const { return getSrc(1); } |
669 Operand *getFalseOperand() const { return getSrc(2); } | 666 Operand *getFalseOperand() const { return getSrc(2); } |
670 void dump(const Cfg *Func) const override; | 667 void dump(const Cfg *Func) const override; |
671 static bool classof(const Inst *Inst) { return Inst->getKind() == Select; } | 668 static bool classof(const Inst *Inst) { return Inst->getKind() == Select; } |
672 | 669 |
673 private: | 670 private: |
674 InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, Operand *Source1, | 671 InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, Operand *Source1, |
675 Operand *Source2); | 672 Operand *Source2); |
676 }; | 673 }; |
677 | 674 |
678 /// Store instruction. The address operand is captured, along with the | 675 /// Store instruction. The address operand is captured, along with the data |
679 /// data operand to be stored into the address. | 676 /// operand to be stored into the address. |
680 class InstStore : public InstHighLevel { | 677 class InstStore : public InstHighLevel { |
681 InstStore() = delete; | 678 InstStore() = delete; |
682 InstStore(const InstStore &) = delete; | 679 InstStore(const InstStore &) = delete; |
683 InstStore &operator=(const InstStore &) = delete; | 680 InstStore &operator=(const InstStore &) = delete; |
684 | 681 |
685 public: | 682 public: |
686 static InstStore *create(Cfg *Func, Operand *Data, Operand *Addr, | 683 static InstStore *create(Cfg *Func, Operand *Data, Operand *Addr, |
687 uint32_t Align = 1) { | 684 uint32_t Align = 1) { |
688 // TODO(kschimpf) Stop ignoring alignment specification. | 685 // TODO(kschimpf) Stop ignoring alignment specification. |
689 (void)Align; | 686 (void)Align; |
690 return new (Func->allocate<InstStore>()) InstStore(Func, Data, Addr); | 687 return new (Func->allocate<InstStore>()) InstStore(Func, Data, Addr); |
691 } | 688 } |
692 Operand *getAddr() const { return getSrc(1); } | 689 Operand *getAddr() const { return getSrc(1); } |
693 Operand *getData() const { return getSrc(0); } | 690 Operand *getData() const { return getSrc(0); } |
694 Variable *getRmwBeacon() const; | 691 Variable *getRmwBeacon() const; |
695 void setRmwBeacon(Variable *Beacon); | 692 void setRmwBeacon(Variable *Beacon); |
696 void dump(const Cfg *Func) const override; | 693 void dump(const Cfg *Func) const override; |
697 static bool classof(const Inst *Inst) { return Inst->getKind() == Store; } | 694 static bool classof(const Inst *Inst) { return Inst->getKind() == Store; } |
698 | 695 |
699 private: | 696 private: |
700 InstStore(Cfg *Func, Operand *Data, Operand *Addr); | 697 InstStore(Cfg *Func, Operand *Data, Operand *Addr); |
701 }; | 698 }; |
702 | 699 |
703 /// Switch instruction. The single source operand is captured as | 700 /// Switch instruction. The single source operand is captured as getSrc(0). |
704 /// getSrc(0). | |
705 class InstSwitch : public InstHighLevel { | 701 class InstSwitch : public InstHighLevel { |
706 InstSwitch() = delete; | 702 InstSwitch() = delete; |
707 InstSwitch(const InstSwitch &) = delete; | 703 InstSwitch(const InstSwitch &) = delete; |
708 InstSwitch &operator=(const InstSwitch &) = delete; | 704 InstSwitch &operator=(const InstSwitch &) = delete; |
709 | 705 |
710 public: | 706 public: |
711 static InstSwitch *create(Cfg *Func, SizeT NumCases, Operand *Source, | 707 static InstSwitch *create(Cfg *Func, SizeT NumCases, Operand *Source, |
712 CfgNode *LabelDefault) { | 708 CfgNode *LabelDefault) { |
713 return new (Func->allocate<InstSwitch>()) | 709 return new (Func->allocate<InstSwitch>()) |
714 InstSwitch(Func, NumCases, Source, LabelDefault); | 710 InstSwitch(Func, NumCases, Source, LabelDefault); |
(...skipping 22 matching lines...) Expand all Loading... |
737 Func->deallocateArrayOf<CfgNode *>(Labels); | 733 Func->deallocateArrayOf<CfgNode *>(Labels); |
738 Inst::destroy(Func); | 734 Inst::destroy(Func); |
739 } | 735 } |
740 | 736 |
741 CfgNode *LabelDefault; | 737 CfgNode *LabelDefault; |
742 SizeT NumCases; /// not including the default case | 738 SizeT NumCases; /// not including the default case |
743 uint64_t *Values; /// size is NumCases | 739 uint64_t *Values; /// size is NumCases |
744 CfgNode **Labels; /// size is NumCases | 740 CfgNode **Labels; /// size is NumCases |
745 }; | 741 }; |
746 | 742 |
747 /// Unreachable instruction. This is a terminator instruction with no | 743 /// Unreachable instruction. This is a terminator instruction with no operands. |
748 /// operands. | |
749 class InstUnreachable : public InstHighLevel { | 744 class InstUnreachable : public InstHighLevel { |
750 InstUnreachable() = delete; | 745 InstUnreachable() = delete; |
751 InstUnreachable(const InstUnreachable &) = delete; | 746 InstUnreachable(const InstUnreachable &) = delete; |
752 InstUnreachable &operator=(const InstUnreachable &) = delete; | 747 InstUnreachable &operator=(const InstUnreachable &) = delete; |
753 | 748 |
754 public: | 749 public: |
755 static InstUnreachable *create(Cfg *Func) { | 750 static InstUnreachable *create(Cfg *Func) { |
756 return new (Func->allocate<InstUnreachable>()) InstUnreachable(Func); | 751 return new (Func->allocate<InstUnreachable>()) InstUnreachable(Func); |
757 } | 752 } |
758 NodeList getTerminatorEdges() const override { return NodeList(); } | 753 NodeList getTerminatorEdges() const override { return NodeList(); } |
759 void dump(const Cfg *Func) const override; | 754 void dump(const Cfg *Func) const override; |
760 static bool classof(const Inst *Inst) { | 755 static bool classof(const Inst *Inst) { |
761 return Inst->getKind() == Unreachable; | 756 return Inst->getKind() == Unreachable; |
762 } | 757 } |
763 | 758 |
764 private: | 759 private: |
765 explicit InstUnreachable(Cfg *Func); | 760 explicit InstUnreachable(Cfg *Func); |
766 }; | 761 }; |
767 | 762 |
768 /// BundleLock instruction. There are no operands. Contains an option | 763 /// BundleLock instruction. There are no operands. Contains an option |
769 /// indicating whether align_to_end is specified. | 764 /// indicating whether align_to_end is specified. |
770 class InstBundleLock : public InstHighLevel { | 765 class InstBundleLock : public InstHighLevel { |
771 InstBundleLock() = delete; | 766 InstBundleLock() = delete; |
772 InstBundleLock(const InstBundleLock &) = delete; | 767 InstBundleLock(const InstBundleLock &) = delete; |
773 InstBundleLock &operator=(const InstBundleLock &) = delete; | 768 InstBundleLock &operator=(const InstBundleLock &) = delete; |
774 | 769 |
775 public: | 770 public: |
776 enum Option { Opt_None, Opt_AlignToEnd }; | 771 enum Option { Opt_None, Opt_AlignToEnd }; |
777 static InstBundleLock *create(Cfg *Func, Option BundleOption) { | 772 static InstBundleLock *create(Cfg *Func, Option BundleOption) { |
778 return new (Func->allocate<InstBundleLock>()) | 773 return new (Func->allocate<InstBundleLock>()) |
779 InstBundleLock(Func, BundleOption); | 774 InstBundleLock(Func, BundleOption); |
780 } | 775 } |
781 void emit(const Cfg *Func) const override; | 776 void emit(const Cfg *Func) const override; |
782 void emitIAS(const Cfg * /* Func */) const override {} | 777 void emitIAS(const Cfg * /* Func */) const override {} |
783 void dump(const Cfg *Func) const override; | 778 void dump(const Cfg *Func) const override; |
784 Option getOption() const { return BundleOption; } | 779 Option getOption() const { return BundleOption; } |
785 static bool classof(const Inst *Inst) { | 780 static bool classof(const Inst *Inst) { |
786 return Inst->getKind() == BundleLock; | 781 return Inst->getKind() == BundleLock; |
787 } | 782 } |
788 | 783 |
789 private: | 784 private: |
790 Option BundleOption; | 785 Option BundleOption; |
791 InstBundleLock(Cfg *Func, Option BundleOption); | 786 InstBundleLock(Cfg *Func, Option BundleOption); |
792 }; | 787 }; |
793 | 788 |
794 /// BundleUnlock instruction. There are no operands. | 789 /// BundleUnlock instruction. There are no operands. |
795 class InstBundleUnlock : public InstHighLevel { | 790 class InstBundleUnlock : public InstHighLevel { |
796 InstBundleUnlock() = delete; | 791 InstBundleUnlock() = delete; |
797 InstBundleUnlock(const InstBundleUnlock &) = delete; | 792 InstBundleUnlock(const InstBundleUnlock &) = delete; |
798 InstBundleUnlock &operator=(const InstBundleUnlock &) = delete; | 793 InstBundleUnlock &operator=(const InstBundleUnlock &) = delete; |
799 | 794 |
800 public: | 795 public: |
801 static InstBundleUnlock *create(Cfg *Func) { | 796 static InstBundleUnlock *create(Cfg *Func) { |
802 return new (Func->allocate<InstBundleUnlock>()) InstBundleUnlock(Func); | 797 return new (Func->allocate<InstBundleUnlock>()) InstBundleUnlock(Func); |
803 } | 798 } |
804 void emit(const Cfg *Func) const override; | 799 void emit(const Cfg *Func) const override; |
805 void emitIAS(const Cfg * /* Func */) const override {} | 800 void emitIAS(const Cfg * /* Func */) const override {} |
806 void dump(const Cfg *Func) const override; | 801 void dump(const Cfg *Func) const override; |
807 static bool classof(const Inst *Inst) { | 802 static bool classof(const Inst *Inst) { |
808 return Inst->getKind() == BundleUnlock; | 803 return Inst->getKind() == BundleUnlock; |
809 } | 804 } |
810 | 805 |
811 private: | 806 private: |
812 explicit InstBundleUnlock(Cfg *Func); | 807 explicit InstBundleUnlock(Cfg *Func); |
813 }; | 808 }; |
814 | 809 |
815 /// FakeDef instruction. This creates a fake definition of a variable, | 810 /// FakeDef instruction. This creates a fake definition of a variable, which is |
816 /// which is how we represent the case when an instruction produces | 811 /// how we represent the case when an instruction produces multiple results. |
817 /// multiple results. This doesn't happen with high-level ICE | 812 /// This doesn't happen with high-level ICE instructions, but might with lowered |
818 /// instructions, but might with lowered instructions. For example, | 813 /// instructions. For example, this would be a way to represent condition flags |
819 /// this would be a way to represent condition flags being modified by | 814 /// being modified by an instruction. |
820 /// an instruction. | |
821 /// | 815 /// |
822 /// It's generally useful to set the optional source operand to be the | 816 /// It's generally useful to set the optional source operand to be the dest |
823 /// dest variable of the instruction that actually produces the FakeDef | 817 /// variable of the instruction that actually produces the FakeDef dest. |
824 /// dest. Otherwise, the original instruction could be dead-code | 818 /// Otherwise, the original instruction could be dead-code eliminated if its |
825 /// eliminated if its dest operand is unused, and therefore the FakeDef | 819 /// dest operand is unused, and therefore the FakeDef dest wouldn't be properly |
826 /// dest wouldn't be properly initialized. | 820 /// initialized. |
827 class InstFakeDef : public InstHighLevel { | 821 class InstFakeDef : public InstHighLevel { |
828 InstFakeDef() = delete; | 822 InstFakeDef() = delete; |
829 InstFakeDef(const InstFakeDef &) = delete; | 823 InstFakeDef(const InstFakeDef &) = delete; |
830 InstFakeDef &operator=(const InstFakeDef &) = delete; | 824 InstFakeDef &operator=(const InstFakeDef &) = delete; |
831 | 825 |
832 public: | 826 public: |
833 static InstFakeDef *create(Cfg *Func, Variable *Dest, | 827 static InstFakeDef *create(Cfg *Func, Variable *Dest, |
834 Variable *Src = nullptr) { | 828 Variable *Src = nullptr) { |
835 return new (Func->allocate<InstFakeDef>()) InstFakeDef(Func, Dest, Src); | 829 return new (Func->allocate<InstFakeDef>()) InstFakeDef(Func, Dest, Src); |
836 } | 830 } |
837 void emit(const Cfg *Func) const override; | 831 void emit(const Cfg *Func) const override; |
838 void emitIAS(const Cfg * /* Func */) const override {} | 832 void emitIAS(const Cfg * /* Func */) const override {} |
839 void dump(const Cfg *Func) const override; | 833 void dump(const Cfg *Func) const override; |
840 static bool classof(const Inst *Inst) { return Inst->getKind() == FakeDef; } | 834 static bool classof(const Inst *Inst) { return Inst->getKind() == FakeDef; } |
841 | 835 |
842 private: | 836 private: |
843 InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src); | 837 InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src); |
844 }; | 838 }; |
845 | 839 |
846 /// FakeUse instruction. This creates a fake use of a variable, to | 840 /// FakeUse instruction. This creates a fake use of a variable, to keep the |
847 /// keep the instruction that produces that variable from being | 841 /// instruction that produces that variable from being dead-code eliminated. |
848 /// dead-code eliminated. This is useful in a variety of lowering | 842 /// This is useful in a variety of lowering situations. The FakeUse instruction |
849 /// situations. The FakeUse instruction has no dest, so it can itself | 843 /// has no dest, so it can itself never be dead-code eliminated. |
850 /// never be dead-code eliminated. | |
851 class InstFakeUse : public InstHighLevel { | 844 class InstFakeUse : public InstHighLevel { |
852 InstFakeUse() = delete; | 845 InstFakeUse() = delete; |
853 InstFakeUse(const InstFakeUse &) = delete; | 846 InstFakeUse(const InstFakeUse &) = delete; |
854 InstFakeUse &operator=(const InstFakeUse &) = delete; | 847 InstFakeUse &operator=(const InstFakeUse &) = delete; |
855 | 848 |
856 public: | 849 public: |
857 static InstFakeUse *create(Cfg *Func, Variable *Src) { | 850 static InstFakeUse *create(Cfg *Func, Variable *Src) { |
858 return new (Func->allocate<InstFakeUse>()) InstFakeUse(Func, Src); | 851 return new (Func->allocate<InstFakeUse>()) InstFakeUse(Func, Src); |
859 } | 852 } |
860 void emit(const Cfg *Func) const override; | 853 void emit(const Cfg *Func) const override; |
861 void emitIAS(const Cfg * /* Func */) const override {} | 854 void emitIAS(const Cfg * /* Func */) const override {} |
862 void dump(const Cfg *Func) const override; | 855 void dump(const Cfg *Func) const override; |
863 static bool classof(const Inst *Inst) { return Inst->getKind() == FakeUse; } | 856 static bool classof(const Inst *Inst) { return Inst->getKind() == FakeUse; } |
864 | 857 |
865 private: | 858 private: |
866 InstFakeUse(Cfg *Func, Variable *Src); | 859 InstFakeUse(Cfg *Func, Variable *Src); |
867 }; | 860 }; |
868 | 861 |
869 /// FakeKill instruction. This "kills" a set of variables by modeling | 862 /// FakeKill instruction. This "kills" a set of variables by modeling a trivial |
870 /// a trivial live range at this instruction for each (implicit) | 863 /// live range at this instruction for each (implicit) variable. The primary use |
871 /// variable. The primary use is to indicate that scratch registers | 864 /// is to indicate that scratch registers are killed after a call, so that the |
872 /// are killed after a call, so that the register allocator won't | 865 /// register allocator won't assign a scratch register to a variable whose live |
873 /// assign a scratch register to a variable whose live range spans a | 866 /// range spans a call. |
874 /// call. | |
875 /// | 867 /// |
876 /// The FakeKill instruction also holds a pointer to the instruction | 868 /// The FakeKill instruction also holds a pointer to the instruction that kills |
877 /// that kills the set of variables, so that if that linked instruction | 869 /// the set of variables, so that if that linked instruction gets dead-code |
878 /// gets dead-code eliminated, the FakeKill instruction will as well. | 870 /// eliminated, the FakeKill instruction will as well. |
879 class InstFakeKill : public InstHighLevel { | 871 class InstFakeKill : public InstHighLevel { |
880 InstFakeKill() = delete; | 872 InstFakeKill() = delete; |
881 InstFakeKill(const InstFakeKill &) = delete; | 873 InstFakeKill(const InstFakeKill &) = delete; |
882 InstFakeKill &operator=(const InstFakeKill &) = delete; | 874 InstFakeKill &operator=(const InstFakeKill &) = delete; |
883 | 875 |
884 public: | 876 public: |
885 static InstFakeKill *create(Cfg *Func, const Inst *Linked) { | 877 static InstFakeKill *create(Cfg *Func, const Inst *Linked) { |
886 return new (Func->allocate<InstFakeKill>()) InstFakeKill(Func, Linked); | 878 return new (Func->allocate<InstFakeKill>()) InstFakeKill(Func, Linked); |
887 } | 879 } |
888 const Inst *getLinked() const { return Linked; } | 880 const Inst *getLinked() const { return Linked; } |
889 void emit(const Cfg *Func) const override; | 881 void emit(const Cfg *Func) const override; |
890 void emitIAS(const Cfg * /* Func */) const override {} | 882 void emitIAS(const Cfg * /* Func */) const override {} |
891 void dump(const Cfg *Func) const override; | 883 void dump(const Cfg *Func) const override; |
892 static bool classof(const Inst *Inst) { return Inst->getKind() == FakeKill; } | 884 static bool classof(const Inst *Inst) { return Inst->getKind() == FakeKill; } |
893 | 885 |
894 private: | 886 private: |
895 InstFakeKill(Cfg *Func, const Inst *Linked); | 887 InstFakeKill(Cfg *Func, const Inst *Linked); |
896 | 888 |
897 /// This instruction is ignored if Linked->isDeleted() is true. | 889 /// This instruction is ignored if Linked->isDeleted() is true. |
898 const Inst *Linked; | 890 const Inst *Linked; |
899 }; | 891 }; |
900 | 892 |
901 /// JumpTable instruction. This represents a jump table that will be | 893 /// JumpTable instruction. This represents a jump table that will be stored in |
902 /// stored in the .rodata section. This is used to track and repoint | 894 /// the .rodata section. This is used to track and repoint the target CfgNodes |
903 /// the target CfgNodes which may change, for example due to | 895 /// which may change, for example due to splitting for phi lowering. |
904 /// splitting for phi lowering. | |
905 class InstJumpTable : public InstHighLevel { | 896 class InstJumpTable : public InstHighLevel { |
906 InstJumpTable() = delete; | 897 InstJumpTable() = delete; |
907 InstJumpTable(const InstJumpTable &) = delete; | 898 InstJumpTable(const InstJumpTable &) = delete; |
908 InstJumpTable &operator=(const InstJumpTable &) = delete; | 899 InstJumpTable &operator=(const InstJumpTable &) = delete; |
909 | 900 |
910 public: | 901 public: |
911 static InstJumpTable *create(Cfg *Func, SizeT NumTargets, CfgNode *Default) { | 902 static InstJumpTable *create(Cfg *Func, SizeT NumTargets, CfgNode *Default) { |
912 return new (Func->allocate<InstJumpTable>()) | 903 return new (Func->allocate<InstJumpTable>()) |
913 InstJumpTable(Func, NumTargets, Default); | 904 InstJumpTable(Func, NumTargets, Default); |
914 } | 905 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
961 assert(Kind <= Target_Max); | 952 assert(Kind <= Target_Max); |
962 } | 953 } |
963 }; | 954 }; |
964 | 955 |
965 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source); | 956 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source); |
966 | 957 |
967 } // end of namespace Ice | 958 } // end of namespace Ice |
968 | 959 |
969 namespace llvm { | 960 namespace llvm { |
970 | 961 |
971 /// Override the default ilist traits so that Inst's private ctor and | 962 /// Override the default ilist traits so that Inst's private ctor and deleted |
972 /// deleted dtor aren't invoked. | 963 /// dtor aren't invoked. |
973 template <> | 964 template <> |
974 struct ilist_traits<Ice::Inst> : public ilist_default_traits<Ice::Inst> { | 965 struct ilist_traits<Ice::Inst> : public ilist_default_traits<Ice::Inst> { |
975 Ice::Inst *createSentinel() const { | 966 Ice::Inst *createSentinel() const { |
976 return static_cast<Ice::Inst *>(&Sentinel); | 967 return static_cast<Ice::Inst *>(&Sentinel); |
977 } | 968 } |
978 static void destroySentinel(Ice::Inst *) {} | 969 static void destroySentinel(Ice::Inst *) {} |
979 Ice::Inst *provideInitialHead() const { return createSentinel(); } | 970 Ice::Inst *provideInitialHead() const { return createSentinel(); } |
980 Ice::Inst *ensureHead(Ice::Inst *) const { return createSentinel(); } | 971 Ice::Inst *ensureHead(Ice::Inst *) const { return createSentinel(); } |
981 static void noteHead(Ice::Inst *, Ice::Inst *) {} | 972 static void noteHead(Ice::Inst *, Ice::Inst *) {} |
982 void deleteNode(Ice::Inst *) {} | 973 void deleteNode(Ice::Inst *) {} |
983 | 974 |
984 private: | 975 private: |
985 mutable ilist_half_node<Ice::Inst> Sentinel; | 976 mutable ilist_half_node<Ice::Inst> Sentinel; |
986 }; | 977 }; |
987 | 978 |
988 } // end of namespace llvm | 979 } // end of namespace llvm |
989 | 980 |
990 #endif // SUBZERO_SRC_ICEINST_H | 981 #endif // SUBZERO_SRC_ICEINST_H |
OLD | NEW |