| 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 // This file declares the Inst class and its target-independent | 10 /// \file |
| 11 // subclasses, which represent the high-level Vanilla ICE instructions | 11 /// This file declares the Inst class and its target-independent |
| 12 // and map roughly 1:1 to LLVM instructions. | 12 /// subclasses, which represent the high-level Vanilla ICE instructions |
| 13 // | 13 /// and map roughly 1:1 to LLVM instructions. |
| 14 /// |
| 14 //===----------------------------------------------------------------------===// | 15 //===----------------------------------------------------------------------===// |
| 15 | 16 |
| 16 #ifndef SUBZERO_SRC_ICEINST_H | 17 #ifndef SUBZERO_SRC_ICEINST_H |
| 17 #define SUBZERO_SRC_ICEINST_H | 18 #define SUBZERO_SRC_ICEINST_H |
| 18 | 19 |
| 19 #include "IceCfg.h" | 20 #include "IceCfg.h" |
| 20 #include "IceDefs.h" | 21 #include "IceDefs.h" |
| 21 #include "IceInst.def" | 22 #include "IceInst.def" |
| 22 #include "IceIntrinsics.h" | 23 #include "IceIntrinsics.h" |
| 23 #include "IceTypes.h" | 24 #include "IceTypes.h" |
| 24 | 25 |
| 25 // TODO: The Cfg structure, and instructions in particular, need to be | 26 // TODO: The Cfg structure, and instructions in particular, need to be |
| 26 // validated for things like valid operand types, valid branch | 27 // validated for things like valid operand types, valid branch |
| 27 // targets, proper ordering of Phi and non-Phi instructions, etc. | 28 // targets, proper ordering of Phi and non-Phi instructions, etc. |
| 28 // Most of the validity checking will be done in the bitcode reader. | 29 // Most of the validity checking will be done in the bitcode reader. |
| 29 // We need a list of everything that should be validated, and tests | 30 // We need a list of everything that should be validated, and tests |
| 30 // for each. | 31 // for each. |
| 31 | 32 |
| 32 namespace Ice { | 33 namespace Ice { |
| 33 | 34 |
| 34 // Base instruction class for ICE. Inst has two subclasses: | 35 /// Base instruction class for ICE. Inst has two subclasses: |
| 35 // InstHighLevel and InstTarget. High-level ICE instructions inherit | 36 /// InstHighLevel and InstTarget. High-level ICE instructions inherit |
| 36 // from InstHighLevel, and low-level (target-specific) ICE | 37 /// from InstHighLevel, and low-level (target-specific) ICE |
| 37 // instructions inherit from InstTarget. | 38 /// instructions inherit from InstTarget. |
| 38 class Inst : public llvm::ilist_node<Inst> { | 39 class Inst : public llvm::ilist_node<Inst> { |
| 39 Inst() = delete; | 40 Inst() = delete; |
| 40 Inst(const Inst &) = delete; | 41 Inst(const Inst &) = delete; |
| 41 Inst &operator=(const Inst &) = delete; | 42 Inst &operator=(const Inst &) = delete; |
| 42 | 43 |
| 43 public: | 44 public: |
| 44 enum InstKind { | 45 enum InstKind { |
| 45 // Arbitrary (alphabetical) order, except put Unreachable first. | 46 // Arbitrary (alphabetical) order, except put Unreachable first. |
| 46 Unreachable, | 47 Unreachable, |
| 47 Alloca, | 48 Alloca, |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 | 99 |
| 99 SizeT getSrcSize() const { return NumSrcs; } | 100 SizeT getSrcSize() const { return NumSrcs; } |
| 100 Operand *getSrc(SizeT I) const { | 101 Operand *getSrc(SizeT I) const { |
| 101 assert(I < getSrcSize()); | 102 assert(I < getSrcSize()); |
| 102 return Srcs[I]; | 103 return Srcs[I]; |
| 103 } | 104 } |
| 104 | 105 |
| 105 bool isLastUse(const Operand *Src) const; | 106 bool isLastUse(const Operand *Src) const; |
| 106 void spliceLivenessInfo(Inst *OrigInst, Inst *SpliceAssn); | 107 void spliceLivenessInfo(Inst *OrigInst, Inst *SpliceAssn); |
| 107 | 108 |
| 108 // Returns a list of out-edges corresponding to a terminator | 109 /// Returns a list of out-edges corresponding to a terminator |
| 109 // instruction, which is the last instruction of the block. | 110 /// instruction, which is the last instruction of the block. |
| 110 virtual NodeList getTerminatorEdges() const { | 111 virtual NodeList getTerminatorEdges() const { |
| 111 // All valid terminator instructions override this method. For | 112 // All valid terminator instructions override this method. For |
| 112 // the default implementation, we assert in case some CfgNode | 113 // the default implementation, we assert in case some CfgNode |
| 113 // is constructed without a terminator instruction at the end. | 114 // is constructed without a terminator instruction at the end. |
| 114 llvm_unreachable( | 115 llvm_unreachable( |
| 115 "getTerminatorEdges() called on a non-terminator instruction"); | 116 "getTerminatorEdges() called on a non-terminator instruction"); |
| 116 return NodeList(); | 117 return NodeList(); |
| 117 } | 118 } |
| 118 virtual bool isUnconditionalBranch() const { return false; } | 119 virtual bool isUnconditionalBranch() const { return false; } |
| 119 // If the instruction is a branch-type instruction with OldNode as a | 120 /// If the instruction is a branch-type instruction with OldNode as a |
| 120 // target, repoint it to NewNode and return true, otherwise return | 121 /// target, repoint it to NewNode and return true, otherwise return |
| 121 // false. Only repoint one instance, even if the instruction has | 122 /// false. Only repoint one instance, even if the instruction has |
| 122 // multiple instances of OldNode as a target. | 123 /// multiple instances of OldNode as a target. |
| 123 virtual bool repointEdge(CfgNode *OldNode, CfgNode *NewNode) { | 124 virtual bool repointEdge(CfgNode *OldNode, CfgNode *NewNode) { |
| 124 (void)OldNode; | 125 (void)OldNode; |
| 125 (void)NewNode; | 126 (void)NewNode; |
| 126 return false; | 127 return false; |
| 127 } | 128 } |
| 128 | 129 |
| 129 virtual bool isSimpleAssign() const { return false; } | 130 virtual bool isSimpleAssign() const { return false; } |
| 130 | 131 |
| 131 void livenessLightweight(Cfg *Func, LivenessBV &Live); | 132 void livenessLightweight(Cfg *Func, LivenessBV &Live); |
| 132 // Calculates liveness for this instruction. Returns true if this | 133 /// Calculates liveness for this instruction. Returns true if this |
| 133 // instruction is (tentatively) still live and should be retained, | 134 /// instruction is (tentatively) still live and should be retained, |
| 134 // and false if this instruction is (tentatively) dead and should be | 135 /// and false if this instruction is (tentatively) dead and should be |
| 135 // deleted. The decision is tentative until the liveness dataflow | 136 /// deleted. The decision is tentative until the liveness dataflow |
| 136 // algorithm has converged, and then a separate pass permanently | 137 /// algorithm has converged, and then a separate pass permanently |
| 137 // deletes dead instructions. | 138 /// deletes dead instructions. |
| 138 bool liveness(InstNumberT InstNumber, LivenessBV &Live, Liveness *Liveness, | 139 bool liveness(InstNumberT InstNumber, LivenessBV &Live, Liveness *Liveness, |
| 139 LiveBeginEndMap *LiveBegin, LiveBeginEndMap *LiveEnd); | 140 LiveBeginEndMap *LiveBegin, LiveBeginEndMap *LiveEnd); |
| 140 | 141 |
| 141 // Get the number of native instructions that this instruction | 142 /// Get the number of native instructions that this instruction |
| 142 // ultimately emits. By default, high-level instructions don't | 143 /// ultimately emits. By default, high-level instructions don't |
| 143 // result in any native instructions, and a target-specific | 144 /// result in any native instructions, and a target-specific |
| 144 // instruction results in a single native instruction. | 145 /// instruction results in a single native instruction. |
| 145 virtual uint32_t getEmitInstCount() const { return 0; } | 146 virtual uint32_t getEmitInstCount() const { return 0; } |
| 146 // TODO(stichnot): Change Inst back to abstract once the g++ build | 147 // TODO(stichnot): Change Inst back to abstract once the g++ build |
| 147 // issue is fixed. llvm::ilist<Ice::Inst> doesn't work under g++ | 148 // issue is fixed. llvm::ilist<Ice::Inst> doesn't work under g++ |
| 148 // because the resize(size_t, Ice::Inst) method is incorrectly | 149 // because the resize(size_t, Ice::Inst) method is incorrectly |
| 149 // declared and thus doesn't allow the abstract class Ice::Inst. | 150 // declared and thus doesn't allow the abstract class Ice::Inst. |
| 150 // The method should be declared resize(size_t, const Ice::Inst &). | 151 // The method should be declared resize(size_t, const Ice::Inst &). |
| 151 // virtual void emit(const Cfg *Func) const = 0; | 152 // virtual void emit(const Cfg *Func) const = 0; |
| 152 // virtual void emitIAS(const Cfg *Func) const = 0; | 153 // virtual void emitIAS(const Cfg *Func) const = 0; |
| 153 virtual void emit(const Cfg *) const { | 154 virtual void emit(const Cfg *) const { |
| 154 llvm_unreachable("emit on abstract class"); | 155 llvm_unreachable("emit on abstract class"); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 172 void addSource(Operand *Src) { | 173 void addSource(Operand *Src) { |
| 173 assert(Src); | 174 assert(Src); |
| 174 assert(NumSrcs < MaxSrcs); | 175 assert(NumSrcs < MaxSrcs); |
| 175 Srcs[NumSrcs++] = Src; | 176 Srcs[NumSrcs++] = Src; |
| 176 } | 177 } |
| 177 void setLastUse(SizeT VarIndex) { | 178 void setLastUse(SizeT VarIndex) { |
| 178 if (VarIndex < CHAR_BIT * sizeof(LiveRangesEnded)) | 179 if (VarIndex < CHAR_BIT * sizeof(LiveRangesEnded)) |
| 179 LiveRangesEnded |= (((LREndedBits)1u) << VarIndex); | 180 LiveRangesEnded |= (((LREndedBits)1u) << VarIndex); |
| 180 } | 181 } |
| 181 void resetLastUses() { LiveRangesEnded = 0; } | 182 void resetLastUses() { LiveRangesEnded = 0; } |
| 182 // The destroy() method lets the instruction cleanly release any | 183 /// The destroy() method lets the instruction cleanly release any |
| 183 // memory that was allocated via the Cfg's allocator. | 184 /// memory that was allocated via the Cfg's allocator. |
| 184 virtual void destroy(Cfg *Func) { Func->deallocateArrayOf<Operand *>(Srcs); } | 185 virtual void destroy(Cfg *Func) { Func->deallocateArrayOf<Operand *>(Srcs); } |
| 185 | 186 |
| 186 const InstKind Kind; | 187 const InstKind Kind; |
| 187 // Number is the instruction number for describing live ranges. | 188 /// Number is the instruction number for describing live ranges. |
| 188 InstNumberT Number; | 189 InstNumberT Number; |
| 189 // Deleted means irrevocably deleted. | 190 /// Deleted means irrevocably deleted. |
| 190 bool Deleted = false; | 191 bool Deleted = false; |
| 191 // Dead means one of two things depending on context: (1) pending | 192 /// Dead means one of two things depending on context: (1) pending |
| 192 // deletion after liveness analysis converges, or (2) marked for | 193 /// deletion after liveness analysis converges, or (2) marked for |
| 193 // deletion during lowering due to a folded bool operation. | 194 /// deletion during lowering due to a folded bool operation. |
| 194 bool Dead = false; | 195 bool Dead = false; |
| 195 // HasSideEffects means the instruction is something like a function | 196 /// HasSideEffects means the instruction is something like a function |
| 196 // call or a volatile load that can't be removed even if its Dest | 197 /// call or a volatile load that can't be removed even if its Dest |
| 197 // variable is not live. | 198 /// variable is not live. |
| 198 bool HasSideEffects = false; | 199 bool HasSideEffects = false; |
| 199 // IsDestNonKillable means that liveness analysis shouldn't consider | 200 /// IsDestNonKillable means that liveness analysis shouldn't consider |
| 200 // this instruction to kill the Dest variable. This is used when | 201 /// this instruction to kill the Dest variable. This is used when |
| 201 // lowering produces two assignments to the same variable. | 202 /// lowering produces two assignments to the same variable. |
| 202 bool IsDestNonKillable = false; | 203 bool IsDestNonKillable = false; |
| 203 | 204 |
| 204 Variable *Dest; | 205 Variable *Dest; |
| 205 const SizeT MaxSrcs; // only used for assert | 206 const SizeT MaxSrcs; // only used for assert |
| 206 SizeT NumSrcs = 0; | 207 SizeT NumSrcs = 0; |
| 207 Operand **Srcs; | 208 Operand **Srcs; |
| 208 | 209 |
| 209 // LiveRangesEnded marks which Variables' live ranges end in this | 210 /// LiveRangesEnded marks which Variables' live ranges end in this |
| 210 // instruction. An instruction can have an arbitrary number of | 211 /// instruction. An instruction can have an arbitrary number of |
| 211 // source operands (e.g. a call instruction), and each source | 212 /// source operands (e.g. a call instruction), and each source |
| 212 // operand can contain 0 or 1 Variable (and target-specific operands | 213 /// operand can contain 0 or 1 Variable (and target-specific operands |
| 213 // could contain more than 1 Variable). All the variables in an | 214 /// could contain more than 1 Variable). All the variables in an |
| 214 // instruction are conceptually flattened and each variable is | 215 /// instruction are conceptually flattened and each variable is |
| 215 // mapped to one bit position of the LiveRangesEnded bit vector. | 216 /// mapped to one bit position of the LiveRangesEnded bit vector. |
| 216 // Only the first CHAR_BIT * sizeof(LREndedBits) variables are | 217 /// Only the first CHAR_BIT * sizeof(LREndedBits) variables are |
| 217 // tracked this way. | 218 /// tracked this way. |
| 218 typedef uint32_t LREndedBits; // only first 32 src operands tracked, sorry | 219 typedef uint32_t LREndedBits; // only first 32 src operands tracked, sorry |
| 219 LREndedBits LiveRangesEnded; | 220 LREndedBits LiveRangesEnded; |
| 220 }; | 221 }; |
| 221 | 222 |
| 222 class InstHighLevel : public Inst { | 223 class InstHighLevel : public Inst { |
| 223 InstHighLevel() = delete; | 224 InstHighLevel() = delete; |
| 224 InstHighLevel(const InstHighLevel &) = delete; | 225 InstHighLevel(const InstHighLevel &) = delete; |
| 225 InstHighLevel &operator=(const InstHighLevel &) = delete; | 226 InstHighLevel &operator=(const InstHighLevel &) = delete; |
| 226 | 227 |
| 227 protected: | 228 protected: |
| 228 InstHighLevel(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) | 229 InstHighLevel(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) |
| 229 : Inst(Func, Kind, MaxSrcs, Dest) {} | 230 : Inst(Func, Kind, MaxSrcs, Dest) {} |
| 230 void emit(const Cfg * /*Func*/) const override { | 231 void emit(const Cfg * /*Func*/) const override { |
| 231 llvm_unreachable("emit() called on a non-lowered instruction"); | 232 llvm_unreachable("emit() called on a non-lowered instruction"); |
| 232 } | 233 } |
| 233 void emitIAS(const Cfg * /*Func*/) const override { | 234 void emitIAS(const Cfg * /*Func*/) const override { |
| 234 llvm_unreachable("emitIAS() called on a non-lowered instruction"); | 235 llvm_unreachable("emitIAS() called on a non-lowered instruction"); |
| 235 } | 236 } |
| 236 }; | 237 }; |
| 237 | 238 |
| 238 // Alloca instruction. This captures the size in bytes as getSrc(0), | 239 /// Alloca instruction. This captures the size in bytes as getSrc(0), |
| 239 // and the required alignment in bytes. The alignment must be either | 240 /// and the required alignment in bytes. The alignment must be either |
| 240 // 0 (no alignment required) or a power of 2. | 241 /// 0 (no alignment required) or a power of 2. |
| 241 class InstAlloca : public InstHighLevel { | 242 class InstAlloca : public InstHighLevel { |
| 242 InstAlloca() = delete; | 243 InstAlloca() = delete; |
| 243 InstAlloca(const InstAlloca &) = delete; | 244 InstAlloca(const InstAlloca &) = delete; |
| 244 InstAlloca &operator=(const InstAlloca &) = delete; | 245 InstAlloca &operator=(const InstAlloca &) = delete; |
| 245 | 246 |
| 246 public: | 247 public: |
| 247 static InstAlloca *create(Cfg *Func, Operand *ByteCount, | 248 static InstAlloca *create(Cfg *Func, Operand *ByteCount, |
| 248 uint32_t AlignInBytes, Variable *Dest) { | 249 uint32_t AlignInBytes, Variable *Dest) { |
| 249 return new (Func->allocate<InstAlloca>()) | 250 return new (Func->allocate<InstAlloca>()) |
| 250 InstAlloca(Func, ByteCount, AlignInBytes, Dest); | 251 InstAlloca(Func, ByteCount, AlignInBytes, Dest); |
| 251 } | 252 } |
| 252 uint32_t getAlignInBytes() const { return AlignInBytes; } | 253 uint32_t getAlignInBytes() const { return AlignInBytes; } |
| 253 Operand *getSizeInBytes() const { return getSrc(0); } | 254 Operand *getSizeInBytes() const { return getSrc(0); } |
| 254 void dump(const Cfg *Func) const override; | 255 void dump(const Cfg *Func) const override; |
| 255 static bool classof(const Inst *Inst) { return Inst->getKind() == Alloca; } | 256 static bool classof(const Inst *Inst) { return Inst->getKind() == Alloca; } |
| 256 | 257 |
| 257 private: | 258 private: |
| 258 InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, | 259 InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, |
| 259 Variable *Dest); | 260 Variable *Dest); |
| 260 | 261 |
| 261 const uint32_t AlignInBytes; | 262 const uint32_t AlignInBytes; |
| 262 }; | 263 }; |
| 263 | 264 |
| 264 // Binary arithmetic instruction. The source operands are captured in | 265 /// Binary arithmetic instruction. The source operands are captured in |
| 265 // getSrc(0) and getSrc(1). | 266 /// getSrc(0) and getSrc(1). |
| 266 class InstArithmetic : public InstHighLevel { | 267 class InstArithmetic : public InstHighLevel { |
| 267 InstArithmetic() = delete; | 268 InstArithmetic() = delete; |
| 268 InstArithmetic(const InstArithmetic &) = delete; | 269 InstArithmetic(const InstArithmetic &) = delete; |
| 269 InstArithmetic &operator=(const InstArithmetic &) = delete; | 270 InstArithmetic &operator=(const InstArithmetic &) = delete; |
| 270 | 271 |
| 271 public: | 272 public: |
| 272 enum OpKind { | 273 enum OpKind { |
| 273 #define X(tag, str, commutative) tag, | 274 #define X(tag, str, commutative) tag, |
| 274 ICEINSTARITHMETIC_TABLE | 275 ICEINSTARITHMETIC_TABLE |
| 275 #undef X | 276 #undef X |
| (...skipping 13 matching lines...) Expand all Loading... |
| 289 return Inst->getKind() == Arithmetic; | 290 return Inst->getKind() == Arithmetic; |
| 290 } | 291 } |
| 291 | 292 |
| 292 private: | 293 private: |
| 293 InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, Operand *Source1, | 294 InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, Operand *Source1, |
| 294 Operand *Source2); | 295 Operand *Source2); |
| 295 | 296 |
| 296 const OpKind Op; | 297 const OpKind Op; |
| 297 }; | 298 }; |
| 298 | 299 |
| 299 // Assignment instruction. The source operand is captured in | 300 /// Assignment instruction. The source operand is captured in |
| 300 // getSrc(0). This is not part of the LLVM bitcode, but is a useful | 301 /// getSrc(0). This is not part of the LLVM bitcode, but is a useful |
| 301 // abstraction for some of the lowering. E.g., if Phi instruction | 302 /// abstraction for some of the lowering. E.g., if Phi instruction |
| 302 // lowering happens before target lowering, or for representing an | 303 /// lowering happens before target lowering, or for representing an |
| 303 // Inttoptr instruction, or as an intermediate step for lowering a | 304 /// Inttoptr instruction, or as an intermediate step for lowering a |
| 304 // Load instruction. | 305 /// Load instruction. |
| 305 class InstAssign : public InstHighLevel { | 306 class InstAssign : public InstHighLevel { |
| 306 InstAssign() = delete; | 307 InstAssign() = delete; |
| 307 InstAssign(const InstAssign &) = delete; | 308 InstAssign(const InstAssign &) = delete; |
| 308 InstAssign &operator=(const InstAssign &) = delete; | 309 InstAssign &operator=(const InstAssign &) = delete; |
| 309 | 310 |
| 310 public: | 311 public: |
| 311 static InstAssign *create(Cfg *Func, Variable *Dest, Operand *Source) { | 312 static InstAssign *create(Cfg *Func, Variable *Dest, Operand *Source) { |
| 312 return new (Func->allocate<InstAssign>()) InstAssign(Func, Dest, Source); | 313 return new (Func->allocate<InstAssign>()) InstAssign(Func, Dest, Source); |
| 313 } | 314 } |
| 314 bool isSimpleAssign() const override { return true; } | 315 bool isSimpleAssign() const override { return true; } |
| 315 void dump(const Cfg *Func) const override; | 316 void dump(const Cfg *Func) const override; |
| 316 static bool classof(const Inst *Inst) { return Inst->getKind() == Assign; } | 317 static bool classof(const Inst *Inst) { return Inst->getKind() == Assign; } |
| 317 | 318 |
| 318 private: | 319 private: |
| 319 InstAssign(Cfg *Func, Variable *Dest, Operand *Source); | 320 InstAssign(Cfg *Func, Variable *Dest, Operand *Source); |
| 320 }; | 321 }; |
| 321 | 322 |
| 322 // Branch instruction. This represents both conditional and | 323 /// Branch instruction. This represents both conditional and |
| 323 // unconditional branches. | 324 /// unconditional branches. |
| 324 class InstBr : public InstHighLevel { | 325 class InstBr : public InstHighLevel { |
| 325 InstBr() = delete; | 326 InstBr() = delete; |
| 326 InstBr(const InstBr &) = delete; | 327 InstBr(const InstBr &) = delete; |
| 327 InstBr &operator=(const InstBr &) = delete; | 328 InstBr &operator=(const InstBr &) = delete; |
| 328 | 329 |
| 329 public: | 330 public: |
| 330 // Create a conditional branch. If TargetTrue==TargetFalse, it is | 331 /// Create a conditional branch. If TargetTrue==TargetFalse, it is |
| 331 // optimized to an unconditional branch. | 332 /// optimized to an unconditional branch. |
| 332 static InstBr *create(Cfg *Func, Operand *Source, CfgNode *TargetTrue, | 333 static InstBr *create(Cfg *Func, Operand *Source, CfgNode *TargetTrue, |
| 333 CfgNode *TargetFalse) { | 334 CfgNode *TargetFalse) { |
| 334 return new (Func->allocate<InstBr>()) | 335 return new (Func->allocate<InstBr>()) |
| 335 InstBr(Func, Source, TargetTrue, TargetFalse); | 336 InstBr(Func, Source, TargetTrue, TargetFalse); |
| 336 } | 337 } |
| 337 // Create an unconditional branch. | 338 /// Create an unconditional branch. |
| 338 static InstBr *create(Cfg *Func, CfgNode *Target) { | 339 static InstBr *create(Cfg *Func, CfgNode *Target) { |
| 339 return new (Func->allocate<InstBr>()) InstBr(Func, Target); | 340 return new (Func->allocate<InstBr>()) InstBr(Func, Target); |
| 340 } | 341 } |
| 341 bool isUnconditional() const { return getTargetTrue() == nullptr; } | 342 bool isUnconditional() const { return getTargetTrue() == nullptr; } |
| 342 Operand *getCondition() const { | 343 Operand *getCondition() const { |
| 343 assert(!isUnconditional()); | 344 assert(!isUnconditional()); |
| 344 return getSrc(0); | 345 return getSrc(0); |
| 345 } | 346 } |
| 346 CfgNode *getTargetTrue() const { return TargetTrue; } | 347 CfgNode *getTargetTrue() const { return TargetTrue; } |
| 347 CfgNode *getTargetFalse() const { return TargetFalse; } | 348 CfgNode *getTargetFalse() const { return TargetFalse; } |
| 348 CfgNode *getTargetUnconditional() const { | 349 CfgNode *getTargetUnconditional() const { |
| 349 assert(isUnconditional()); | 350 assert(isUnconditional()); |
| 350 return getTargetFalse(); | 351 return getTargetFalse(); |
| 351 } | 352 } |
| 352 NodeList getTerminatorEdges() const override; | 353 NodeList getTerminatorEdges() const override; |
| 353 bool isUnconditionalBranch() const override { return isUnconditional(); } | 354 bool isUnconditionalBranch() const override { return isUnconditional(); } |
| 354 bool repointEdge(CfgNode *OldNode, CfgNode *NewNode) override; | 355 bool repointEdge(CfgNode *OldNode, CfgNode *NewNode) override; |
| 355 void dump(const Cfg *Func) const override; | 356 void dump(const Cfg *Func) const override; |
| 356 static bool classof(const Inst *Inst) { return Inst->getKind() == Br; } | 357 static bool classof(const Inst *Inst) { return Inst->getKind() == Br; } |
| 357 | 358 |
| 358 private: | 359 private: |
| 359 // Conditional branch | 360 /// Conditional branch |
| 360 InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, CfgNode *TargetFalse); | 361 InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, CfgNode *TargetFalse); |
| 361 // Unconditional branch | 362 /// Unconditional branch |
| 362 InstBr(Cfg *Func, CfgNode *Target); | 363 InstBr(Cfg *Func, CfgNode *Target); |
| 363 | 364 |
| 364 CfgNode *TargetFalse; // Doubles as unconditional branch target | 365 CfgNode *TargetFalse; /// Doubles as unconditional branch target |
| 365 CfgNode *TargetTrue; // nullptr if unconditional branch | 366 CfgNode *TargetTrue; /// nullptr if unconditional branch |
| 366 }; | 367 }; |
| 367 | 368 |
| 368 // Call instruction. The call target is captured as getSrc(0), and | 369 /// Call instruction. The call target is captured as getSrc(0), and |
| 369 // arg I is captured as getSrc(I+1). | 370 /// arg I is captured as getSrc(I+1). |
| 370 class InstCall : public InstHighLevel { | 371 class InstCall : public InstHighLevel { |
| 371 InstCall() = delete; | 372 InstCall() = delete; |
| 372 InstCall(const InstCall &) = delete; | 373 InstCall(const InstCall &) = delete; |
| 373 InstCall &operator=(const InstCall &) = delete; | 374 InstCall &operator=(const InstCall &) = delete; |
| 374 | 375 |
| 375 public: | 376 public: |
| 376 static InstCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest, | 377 static InstCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest, |
| 377 Operand *CallTarget, bool HasTailCall) { | 378 Operand *CallTarget, bool HasTailCall) { |
| 378 // Set HasSideEffects to true so that the call instruction can't be | 379 /// Set HasSideEffects to true so that the call instruction can't be |
| 379 // dead-code eliminated. IntrinsicCalls can override this if the | 380 /// dead-code eliminated. IntrinsicCalls can override this if the |
| 380 // particular intrinsic is deletable and has no side-effects. | 381 /// particular intrinsic is deletable and has no side-effects. |
| 381 const bool HasSideEffects = true; | 382 const bool HasSideEffects = true; |
| 382 const InstKind Kind = Inst::Call; | 383 const InstKind Kind = Inst::Call; |
| 383 return new (Func->allocate<InstCall>()) InstCall( | 384 return new (Func->allocate<InstCall>()) InstCall( |
| 384 Func, NumArgs, Dest, CallTarget, HasTailCall, HasSideEffects, Kind); | 385 Func, NumArgs, Dest, CallTarget, HasTailCall, HasSideEffects, Kind); |
| 385 } | 386 } |
| 386 void addArg(Operand *Arg) { addSource(Arg); } | 387 void addArg(Operand *Arg) { addSource(Arg); } |
| 387 Operand *getCallTarget() const { return getSrc(0); } | 388 Operand *getCallTarget() const { return getSrc(0); } |
| 388 Operand *getArg(SizeT I) const { return getSrc(I + 1); } | 389 Operand *getArg(SizeT I) const { return getSrc(I + 1); } |
| 389 SizeT getNumArgs() const { return getSrcSize() - 1; } | 390 SizeT getNumArgs() const { return getSrcSize() - 1; } |
| 390 bool isTailcall() const { return HasTailCall; } | 391 bool isTailcall() const { return HasTailCall; } |
| 391 void dump(const Cfg *Func) const override; | 392 void dump(const Cfg *Func) const override; |
| 392 static bool classof(const Inst *Inst) { return Inst->getKind() == Call; } | 393 static bool classof(const Inst *Inst) { return Inst->getKind() == Call; } |
| 393 Type getReturnType() const; | 394 Type getReturnType() const; |
| 394 | 395 |
| 395 protected: | 396 protected: |
| 396 InstCall(Cfg *Func, SizeT NumArgs, Variable *Dest, Operand *CallTarget, | 397 InstCall(Cfg *Func, SizeT NumArgs, Variable *Dest, Operand *CallTarget, |
| 397 bool HasTailCall, bool HasSideEff, InstKind Kind) | 398 bool HasTailCall, bool HasSideEff, InstKind Kind) |
| 398 : InstHighLevel(Func, Kind, NumArgs + 1, Dest), HasTailCall(HasTailCall) { | 399 : InstHighLevel(Func, Kind, NumArgs + 1, Dest), HasTailCall(HasTailCall) { |
| 399 HasSideEffects = HasSideEff; | 400 HasSideEffects = HasSideEff; |
| 400 addSource(CallTarget); | 401 addSource(CallTarget); |
| 401 } | 402 } |
| 402 | 403 |
| 403 private: | 404 private: |
| 404 bool HasTailCall; | 405 bool HasTailCall; |
| 405 }; | 406 }; |
| 406 | 407 |
| 407 // Cast instruction (a.k.a. conversion operation). | 408 /// Cast instruction (a.k.a. conversion operation). |
| 408 class InstCast : public InstHighLevel { | 409 class InstCast : public InstHighLevel { |
| 409 InstCast() = delete; | 410 InstCast() = delete; |
| 410 InstCast(const InstCast &) = delete; | 411 InstCast(const InstCast &) = delete; |
| 411 InstCast &operator=(const InstCast &) = delete; | 412 InstCast &operator=(const InstCast &) = delete; |
| 412 | 413 |
| 413 public: | 414 public: |
| 414 enum OpKind { | 415 enum OpKind { |
| 415 #define X(tag, str) tag, | 416 #define X(tag, str) tag, |
| 416 ICEINSTCAST_TABLE | 417 ICEINSTCAST_TABLE |
| 417 #undef X | 418 #undef X |
| (...skipping 10 matching lines...) Expand all Loading... |
| 428 OpKind getCastKind() const { return CastKind; } | 429 OpKind getCastKind() const { return CastKind; } |
| 429 void dump(const Cfg *Func) const override; | 430 void dump(const Cfg *Func) const override; |
| 430 static bool classof(const Inst *Inst) { return Inst->getKind() == Cast; } | 431 static bool classof(const Inst *Inst) { return Inst->getKind() == Cast; } |
| 431 | 432 |
| 432 private: | 433 private: |
| 433 InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source); | 434 InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source); |
| 434 | 435 |
| 435 const OpKind CastKind; | 436 const OpKind CastKind; |
| 436 }; | 437 }; |
| 437 | 438 |
| 438 // ExtractElement instruction. | 439 /// ExtractElement instruction. |
| 439 class InstExtractElement : public InstHighLevel { | 440 class InstExtractElement : public InstHighLevel { |
| 440 InstExtractElement() = delete; | 441 InstExtractElement() = delete; |
| 441 InstExtractElement(const InstExtractElement &) = delete; | 442 InstExtractElement(const InstExtractElement &) = delete; |
| 442 InstExtractElement &operator=(const InstExtractElement &) = delete; | 443 InstExtractElement &operator=(const InstExtractElement &) = delete; |
| 443 | 444 |
| 444 public: | 445 public: |
| 445 static InstExtractElement *create(Cfg *Func, Variable *Dest, Operand *Source1, | 446 static InstExtractElement *create(Cfg *Func, Variable *Dest, Operand *Source1, |
| 446 Operand *Source2) { | 447 Operand *Source2) { |
| 447 return new (Func->allocate<InstExtractElement>()) | 448 return new (Func->allocate<InstExtractElement>()) |
| 448 InstExtractElement(Func, Dest, Source1, Source2); | 449 InstExtractElement(Func, Dest, Source1, Source2); |
| 449 } | 450 } |
| 450 | 451 |
| 451 void dump(const Cfg *Func) const override; | 452 void dump(const Cfg *Func) const override; |
| 452 static bool classof(const Inst *Inst) { | 453 static bool classof(const Inst *Inst) { |
| 453 return Inst->getKind() == ExtractElement; | 454 return Inst->getKind() == ExtractElement; |
| 454 } | 455 } |
| 455 | 456 |
| 456 private: | 457 private: |
| 457 InstExtractElement(Cfg *Func, Variable *Dest, Operand *Source1, | 458 InstExtractElement(Cfg *Func, Variable *Dest, Operand *Source1, |
| 458 Operand *Source2); | 459 Operand *Source2); |
| 459 }; | 460 }; |
| 460 | 461 |
| 461 // Floating-point comparison instruction. The source operands are | 462 /// Floating-point comparison instruction. The source operands are |
| 462 // captured in getSrc(0) and getSrc(1). | 463 /// captured in getSrc(0) and getSrc(1). |
| 463 class InstFcmp : public InstHighLevel { | 464 class InstFcmp : public InstHighLevel { |
| 464 InstFcmp() = delete; | 465 InstFcmp() = delete; |
| 465 InstFcmp(const InstFcmp &) = delete; | 466 InstFcmp(const InstFcmp &) = delete; |
| 466 InstFcmp &operator=(const InstFcmp &) = delete; | 467 InstFcmp &operator=(const InstFcmp &) = delete; |
| 467 | 468 |
| 468 public: | 469 public: |
| 469 enum FCond { | 470 enum FCond { |
| 470 #define X(tag, str) tag, | 471 #define X(tag, str) tag, |
| 471 ICEINSTFCMP_TABLE | 472 ICEINSTFCMP_TABLE |
| 472 #undef X | 473 #undef X |
| 473 _num | 474 _num |
| 474 }; | 475 }; |
| 475 | 476 |
| 476 static InstFcmp *create(Cfg *Func, FCond Condition, Variable *Dest, | 477 static InstFcmp *create(Cfg *Func, FCond Condition, Variable *Dest, |
| 477 Operand *Source1, Operand *Source2) { | 478 Operand *Source1, Operand *Source2) { |
| 478 return new (Func->allocate<InstFcmp>()) | 479 return new (Func->allocate<InstFcmp>()) |
| 479 InstFcmp(Func, Condition, Dest, Source1, Source2); | 480 InstFcmp(Func, Condition, Dest, Source1, Source2); |
| 480 } | 481 } |
| 481 FCond getCondition() const { return Condition; } | 482 FCond getCondition() const { return Condition; } |
| 482 void dump(const Cfg *Func) const override; | 483 void dump(const Cfg *Func) const override; |
| 483 static bool classof(const Inst *Inst) { return Inst->getKind() == Fcmp; } | 484 static bool classof(const Inst *Inst) { return Inst->getKind() == Fcmp; } |
| 484 | 485 |
| 485 private: | 486 private: |
| 486 InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1, | 487 InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1, |
| 487 Operand *Source2); | 488 Operand *Source2); |
| 488 | 489 |
| 489 const FCond Condition; | 490 const FCond Condition; |
| 490 }; | 491 }; |
| 491 | 492 |
| 492 // Integer comparison instruction. The source operands are captured | 493 /// Integer comparison instruction. The source operands are captured |
| 493 // in getSrc(0) and getSrc(1). | 494 /// in getSrc(0) and getSrc(1). |
| 494 class InstIcmp : public InstHighLevel { | 495 class InstIcmp : public InstHighLevel { |
| 495 InstIcmp() = delete; | 496 InstIcmp() = delete; |
| 496 InstIcmp(const InstIcmp &) = delete; | 497 InstIcmp(const InstIcmp &) = delete; |
| 497 InstIcmp &operator=(const InstIcmp &) = delete; | 498 InstIcmp &operator=(const InstIcmp &) = delete; |
| 498 | 499 |
| 499 public: | 500 public: |
| 500 enum ICond { | 501 enum ICond { |
| 501 #define X(tag, str) tag, | 502 #define X(tag, str) tag, |
| 502 ICEINSTICMP_TABLE | 503 ICEINSTICMP_TABLE |
| 503 #undef X | 504 #undef X |
| 504 _num | 505 _num |
| 505 }; | 506 }; |
| 506 | 507 |
| 507 static InstIcmp *create(Cfg *Func, ICond Condition, Variable *Dest, | 508 static InstIcmp *create(Cfg *Func, ICond Condition, Variable *Dest, |
| 508 Operand *Source1, Operand *Source2) { | 509 Operand *Source1, Operand *Source2) { |
| 509 return new (Func->allocate<InstIcmp>()) | 510 return new (Func->allocate<InstIcmp>()) |
| 510 InstIcmp(Func, Condition, Dest, Source1, Source2); | 511 InstIcmp(Func, Condition, Dest, Source1, Source2); |
| 511 } | 512 } |
| 512 ICond getCondition() const { return Condition; } | 513 ICond getCondition() const { return Condition; } |
| 513 void dump(const Cfg *Func) const override; | 514 void dump(const Cfg *Func) const override; |
| 514 static bool classof(const Inst *Inst) { return Inst->getKind() == Icmp; } | 515 static bool classof(const Inst *Inst) { return Inst->getKind() == Icmp; } |
| 515 | 516 |
| 516 private: | 517 private: |
| 517 InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1, | 518 InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1, |
| 518 Operand *Source2); | 519 Operand *Source2); |
| 519 | 520 |
| 520 const ICond Condition; | 521 const ICond Condition; |
| 521 }; | 522 }; |
| 522 | 523 |
| 523 // InsertElement instruction. | 524 /// InsertElement instruction. |
| 524 class InstInsertElement : public InstHighLevel { | 525 class InstInsertElement : public InstHighLevel { |
| 525 InstInsertElement() = delete; | 526 InstInsertElement() = delete; |
| 526 InstInsertElement(const InstInsertElement &) = delete; | 527 InstInsertElement(const InstInsertElement &) = delete; |
| 527 InstInsertElement &operator=(const InstInsertElement &) = delete; | 528 InstInsertElement &operator=(const InstInsertElement &) = delete; |
| 528 | 529 |
| 529 public: | 530 public: |
| 530 static InstInsertElement *create(Cfg *Func, Variable *Dest, Operand *Source1, | 531 static InstInsertElement *create(Cfg *Func, Variable *Dest, Operand *Source1, |
| 531 Operand *Source2, Operand *Source3) { | 532 Operand *Source2, Operand *Source3) { |
| 532 return new (Func->allocate<InstInsertElement>()) | 533 return new (Func->allocate<InstInsertElement>()) |
| 533 InstInsertElement(Func, Dest, Source1, Source2, Source3); | 534 InstInsertElement(Func, Dest, Source1, Source2, Source3); |
| 534 } | 535 } |
| 535 | 536 |
| 536 void dump(const Cfg *Func) const override; | 537 void dump(const Cfg *Func) const override; |
| 537 static bool classof(const Inst *Inst) { | 538 static bool classof(const Inst *Inst) { |
| 538 return Inst->getKind() == InsertElement; | 539 return Inst->getKind() == InsertElement; |
| 539 } | 540 } |
| 540 | 541 |
| 541 private: | 542 private: |
| 542 InstInsertElement(Cfg *Func, Variable *Dest, Operand *Source1, | 543 InstInsertElement(Cfg *Func, Variable *Dest, Operand *Source1, |
| 543 Operand *Source2, Operand *Source3); | 544 Operand *Source2, Operand *Source3); |
| 544 }; | 545 }; |
| 545 | 546 |
| 546 // Call to an intrinsic function. The call target is captured as getSrc(0), | 547 /// Call to an intrinsic function. The call target is captured as getSrc(0), |
| 547 // and arg I is captured as getSrc(I+1). | 548 /// and arg I is captured as getSrc(I+1). |
| 548 class InstIntrinsicCall : public InstCall { | 549 class InstIntrinsicCall : public InstCall { |
| 549 InstIntrinsicCall() = delete; | 550 InstIntrinsicCall() = delete; |
| 550 InstIntrinsicCall(const InstIntrinsicCall &) = delete; | 551 InstIntrinsicCall(const InstIntrinsicCall &) = delete; |
| 551 InstIntrinsicCall &operator=(const InstIntrinsicCall &) = delete; | 552 InstIntrinsicCall &operator=(const InstIntrinsicCall &) = delete; |
| 552 | 553 |
| 553 public: | 554 public: |
| 554 static InstIntrinsicCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest, | 555 static InstIntrinsicCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest, |
| 555 Operand *CallTarget, | 556 Operand *CallTarget, |
| 556 const Intrinsics::IntrinsicInfo &Info) { | 557 const Intrinsics::IntrinsicInfo &Info) { |
| 557 return new (Func->allocate<InstIntrinsicCall>()) | 558 return new (Func->allocate<InstIntrinsicCall>()) |
| 558 InstIntrinsicCall(Func, NumArgs, Dest, CallTarget, Info); | 559 InstIntrinsicCall(Func, NumArgs, Dest, CallTarget, Info); |
| 559 } | 560 } |
| 560 static bool classof(const Inst *Inst) { | 561 static bool classof(const Inst *Inst) { |
| 561 return Inst->getKind() == IntrinsicCall; | 562 return Inst->getKind() == IntrinsicCall; |
| 562 } | 563 } |
| 563 | 564 |
| 564 Intrinsics::IntrinsicInfo getIntrinsicInfo() const { return Info; } | 565 Intrinsics::IntrinsicInfo getIntrinsicInfo() const { return Info; } |
| 565 | 566 |
| 566 private: | 567 private: |
| 567 InstIntrinsicCall(Cfg *Func, SizeT NumArgs, Variable *Dest, | 568 InstIntrinsicCall(Cfg *Func, SizeT NumArgs, Variable *Dest, |
| 568 Operand *CallTarget, const Intrinsics::IntrinsicInfo &Info) | 569 Operand *CallTarget, const Intrinsics::IntrinsicInfo &Info) |
| 569 : InstCall(Func, NumArgs, Dest, CallTarget, false, Info.HasSideEffects, | 570 : InstCall(Func, NumArgs, Dest, CallTarget, false, Info.HasSideEffects, |
| 570 Inst::IntrinsicCall), | 571 Inst::IntrinsicCall), |
| 571 Info(Info) {} | 572 Info(Info) {} |
| 572 | 573 |
| 573 const Intrinsics::IntrinsicInfo Info; | 574 const Intrinsics::IntrinsicInfo Info; |
| 574 }; | 575 }; |
| 575 | 576 |
| 576 // Load instruction. The source address is captured in getSrc(0). | 577 /// Load instruction. The source address is captured in getSrc(0). |
| 577 class InstLoad : public InstHighLevel { | 578 class InstLoad : public InstHighLevel { |
| 578 InstLoad() = delete; | 579 InstLoad() = delete; |
| 579 InstLoad(const InstLoad &) = delete; | 580 InstLoad(const InstLoad &) = delete; |
| 580 InstLoad &operator=(const InstLoad &) = delete; | 581 InstLoad &operator=(const InstLoad &) = delete; |
| 581 | 582 |
| 582 public: | 583 public: |
| 583 static InstLoad *create(Cfg *Func, Variable *Dest, Operand *SourceAddr, | 584 static InstLoad *create(Cfg *Func, Variable *Dest, Operand *SourceAddr, |
| 584 uint32_t Align = 1) { | 585 uint32_t Align = 1) { |
| 585 // TODO(kschimpf) Stop ignoring alignment specification. | 586 // TODO(kschimpf) Stop ignoring alignment specification. |
| 586 (void)Align; | 587 (void)Align; |
| 587 return new (Func->allocate<InstLoad>()) InstLoad(Func, Dest, SourceAddr); | 588 return new (Func->allocate<InstLoad>()) InstLoad(Func, Dest, SourceAddr); |
| 588 } | 589 } |
| 589 Operand *getSourceAddress() const { return getSrc(0); } | 590 Operand *getSourceAddress() const { return getSrc(0); } |
| 590 void dump(const Cfg *Func) const override; | 591 void dump(const Cfg *Func) const override; |
| 591 static bool classof(const Inst *Inst) { return Inst->getKind() == Load; } | 592 static bool classof(const Inst *Inst) { return Inst->getKind() == Load; } |
| 592 | 593 |
| 593 private: | 594 private: |
| 594 InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr); | 595 InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr); |
| 595 }; | 596 }; |
| 596 | 597 |
| 597 // Phi instruction. For incoming edge I, the node is Labels[I] and | 598 /// Phi instruction. For incoming edge I, the node is Labels[I] and |
| 598 // the Phi source operand is getSrc(I). | 599 /// the Phi source operand is getSrc(I). |
| 599 class InstPhi : public InstHighLevel { | 600 class InstPhi : public InstHighLevel { |
| 600 InstPhi() = delete; | 601 InstPhi() = delete; |
| 601 InstPhi(const InstPhi &) = delete; | 602 InstPhi(const InstPhi &) = delete; |
| 602 InstPhi &operator=(const InstPhi &) = delete; | 603 InstPhi &operator=(const InstPhi &) = delete; |
| 603 | 604 |
| 604 public: | 605 public: |
| 605 static InstPhi *create(Cfg *Func, SizeT MaxSrcs, Variable *Dest) { | 606 static InstPhi *create(Cfg *Func, SizeT MaxSrcs, Variable *Dest) { |
| 606 return new (Func->allocate<InstPhi>()) InstPhi(Func, MaxSrcs, Dest); | 607 return new (Func->allocate<InstPhi>()) InstPhi(Func, MaxSrcs, Dest); |
| 607 } | 608 } |
| 608 void addArgument(Operand *Source, CfgNode *Label); | 609 void addArgument(Operand *Source, CfgNode *Label); |
| 609 Operand *getOperandForTarget(CfgNode *Target) const; | 610 Operand *getOperandForTarget(CfgNode *Target) const; |
| 610 CfgNode *getLabel(SizeT Index) const { return Labels[Index]; } | 611 CfgNode *getLabel(SizeT Index) const { return Labels[Index]; } |
| 611 void livenessPhiOperand(LivenessBV &Live, CfgNode *Target, | 612 void livenessPhiOperand(LivenessBV &Live, CfgNode *Target, |
| 612 Liveness *Liveness); | 613 Liveness *Liveness); |
| 613 Inst *lower(Cfg *Func); | 614 Inst *lower(Cfg *Func); |
| 614 void dump(const Cfg *Func) const override; | 615 void dump(const Cfg *Func) const override; |
| 615 static bool classof(const Inst *Inst) { return Inst->getKind() == Phi; } | 616 static bool classof(const Inst *Inst) { return Inst->getKind() == Phi; } |
| 616 | 617 |
| 617 private: | 618 private: |
| 618 InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest); | 619 InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest); |
| 619 void destroy(Cfg *Func) override { | 620 void destroy(Cfg *Func) override { |
| 620 Func->deallocateArrayOf<CfgNode *>(Labels); | 621 Func->deallocateArrayOf<CfgNode *>(Labels); |
| 621 Inst::destroy(Func); | 622 Inst::destroy(Func); |
| 622 } | 623 } |
| 623 | 624 |
| 624 // Labels[] duplicates the InEdges[] information in the enclosing | 625 /// Labels[] duplicates the InEdges[] information in the enclosing |
| 625 // CfgNode, but the Phi instruction is created before InEdges[] | 626 /// CfgNode, but the Phi instruction is created before InEdges[] |
| 626 // is available, so it's more complicated to share the list. | 627 /// is available, so it's more complicated to share the list. |
| 627 CfgNode **Labels; | 628 CfgNode **Labels; |
| 628 }; | 629 }; |
| 629 | 630 |
| 630 // Ret instruction. The return value is captured in getSrc(0), but if | 631 /// Ret instruction. The return value is captured in getSrc(0), but if |
| 631 // there is no return value (void-type function), then | 632 /// there is no return value (void-type function), then |
| 632 // getSrcSize()==0 and hasRetValue()==false. | 633 /// getSrcSize()==0 and hasRetValue()==false. |
| 633 class InstRet : public InstHighLevel { | 634 class InstRet : public InstHighLevel { |
| 634 InstRet() = delete; | 635 InstRet() = delete; |
| 635 InstRet(const InstRet &) = delete; | 636 InstRet(const InstRet &) = delete; |
| 636 InstRet &operator=(const InstRet &) = delete; | 637 InstRet &operator=(const InstRet &) = delete; |
| 637 | 638 |
| 638 public: | 639 public: |
| 639 static InstRet *create(Cfg *Func, Operand *RetValue = nullptr) { | 640 static InstRet *create(Cfg *Func, Operand *RetValue = nullptr) { |
| 640 return new (Func->allocate<InstRet>()) InstRet(Func, RetValue); | 641 return new (Func->allocate<InstRet>()) InstRet(Func, RetValue); |
| 641 } | 642 } |
| 642 bool hasRetValue() const { return getSrcSize(); } | 643 bool hasRetValue() const { return getSrcSize(); } |
| 643 Operand *getRetValue() const { | 644 Operand *getRetValue() const { |
| 644 assert(hasRetValue()); | 645 assert(hasRetValue()); |
| 645 return getSrc(0); | 646 return getSrc(0); |
| 646 } | 647 } |
| 647 NodeList getTerminatorEdges() const override { return NodeList(); } | 648 NodeList getTerminatorEdges() const override { return NodeList(); } |
| 648 void dump(const Cfg *Func) const override; | 649 void dump(const Cfg *Func) const override; |
| 649 static bool classof(const Inst *Inst) { return Inst->getKind() == Ret; } | 650 static bool classof(const Inst *Inst) { return Inst->getKind() == Ret; } |
| 650 | 651 |
| 651 private: | 652 private: |
| 652 InstRet(Cfg *Func, Operand *RetValue); | 653 InstRet(Cfg *Func, Operand *RetValue); |
| 653 }; | 654 }; |
| 654 | 655 |
| 655 // Select instruction. The condition, true, and false operands are captured. | 656 /// Select instruction. The condition, true, and false operands are captured. |
| 656 class InstSelect : public InstHighLevel { | 657 class InstSelect : public InstHighLevel { |
| 657 InstSelect() = delete; | 658 InstSelect() = delete; |
| 658 InstSelect(const InstSelect &) = delete; | 659 InstSelect(const InstSelect &) = delete; |
| 659 InstSelect &operator=(const InstSelect &) = delete; | 660 InstSelect &operator=(const InstSelect &) = delete; |
| 660 | 661 |
| 661 public: | 662 public: |
| 662 static InstSelect *create(Cfg *Func, Variable *Dest, Operand *Condition, | 663 static InstSelect *create(Cfg *Func, Variable *Dest, Operand *Condition, |
| 663 Operand *SourceTrue, Operand *SourceFalse) { | 664 Operand *SourceTrue, Operand *SourceFalse) { |
| 664 return new (Func->allocate<InstSelect>()) | 665 return new (Func->allocate<InstSelect>()) |
| 665 InstSelect(Func, Dest, Condition, SourceTrue, SourceFalse); | 666 InstSelect(Func, Dest, Condition, SourceTrue, SourceFalse); |
| 666 } | 667 } |
| 667 Operand *getCondition() const { return getSrc(0); } | 668 Operand *getCondition() const { return getSrc(0); } |
| 668 Operand *getTrueOperand() const { return getSrc(1); } | 669 Operand *getTrueOperand() const { return getSrc(1); } |
| 669 Operand *getFalseOperand() const { return getSrc(2); } | 670 Operand *getFalseOperand() const { return getSrc(2); } |
| 670 void dump(const Cfg *Func) const override; | 671 void dump(const Cfg *Func) const override; |
| 671 static bool classof(const Inst *Inst) { return Inst->getKind() == Select; } | 672 static bool classof(const Inst *Inst) { return Inst->getKind() == Select; } |
| 672 | 673 |
| 673 private: | 674 private: |
| 674 InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, Operand *Source1, | 675 InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, Operand *Source1, |
| 675 Operand *Source2); | 676 Operand *Source2); |
| 676 }; | 677 }; |
| 677 | 678 |
| 678 // Store instruction. The address operand is captured, along with the | 679 /// Store instruction. The address operand is captured, along with the |
| 679 // data operand to be stored into the address. | 680 /// data operand to be stored into the address. |
| 680 class InstStore : public InstHighLevel { | 681 class InstStore : public InstHighLevel { |
| 681 InstStore() = delete; | 682 InstStore() = delete; |
| 682 InstStore(const InstStore &) = delete; | 683 InstStore(const InstStore &) = delete; |
| 683 InstStore &operator=(const InstStore &) = delete; | 684 InstStore &operator=(const InstStore &) = delete; |
| 684 | 685 |
| 685 public: | 686 public: |
| 686 static InstStore *create(Cfg *Func, Operand *Data, Operand *Addr, | 687 static InstStore *create(Cfg *Func, Operand *Data, Operand *Addr, |
| 687 uint32_t Align = 1) { | 688 uint32_t Align = 1) { |
| 688 // TODO(kschimpf) Stop ignoring alignment specification. | 689 // TODO(kschimpf) Stop ignoring alignment specification. |
| 689 (void)Align; | 690 (void)Align; |
| 690 return new (Func->allocate<InstStore>()) InstStore(Func, Data, Addr); | 691 return new (Func->allocate<InstStore>()) InstStore(Func, Data, Addr); |
| 691 } | 692 } |
| 692 Operand *getAddr() const { return getSrc(1); } | 693 Operand *getAddr() const { return getSrc(1); } |
| 693 Operand *getData() const { return getSrc(0); } | 694 Operand *getData() const { return getSrc(0); } |
| 694 Variable *getRmwBeacon() const { return llvm::dyn_cast<Variable>(getSrc(2)); } | 695 Variable *getRmwBeacon() const { return llvm::dyn_cast<Variable>(getSrc(2)); } |
| 695 void setRmwBeacon(Variable *Beacon); | 696 void setRmwBeacon(Variable *Beacon); |
| 696 void dump(const Cfg *Func) const override; | 697 void dump(const Cfg *Func) const override; |
| 697 static bool classof(const Inst *Inst) { return Inst->getKind() == Store; } | 698 static bool classof(const Inst *Inst) { return Inst->getKind() == Store; } |
| 698 | 699 |
| 699 private: | 700 private: |
| 700 InstStore(Cfg *Func, Operand *Data, Operand *Addr); | 701 InstStore(Cfg *Func, Operand *Data, Operand *Addr); |
| 701 }; | 702 }; |
| 702 | 703 |
| 703 // Switch instruction. The single source operand is captured as | 704 /// Switch instruction. The single source operand is captured as |
| 704 // getSrc(0). | 705 /// getSrc(0). |
| 705 class InstSwitch : public InstHighLevel { | 706 class InstSwitch : public InstHighLevel { |
| 706 InstSwitch() = delete; | 707 InstSwitch() = delete; |
| 707 InstSwitch(const InstSwitch &) = delete; | 708 InstSwitch(const InstSwitch &) = delete; |
| 708 InstSwitch &operator=(const InstSwitch &) = delete; | 709 InstSwitch &operator=(const InstSwitch &) = delete; |
| 709 | 710 |
| 710 public: | 711 public: |
| 711 static InstSwitch *create(Cfg *Func, SizeT NumCases, Operand *Source, | 712 static InstSwitch *create(Cfg *Func, SizeT NumCases, Operand *Source, |
| 712 CfgNode *LabelDefault) { | 713 CfgNode *LabelDefault) { |
| 713 return new (Func->allocate<InstSwitch>()) | 714 return new (Func->allocate<InstSwitch>()) |
| 714 InstSwitch(Func, NumCases, Source, LabelDefault); | 715 InstSwitch(Func, NumCases, Source, LabelDefault); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 732 | 733 |
| 733 private: | 734 private: |
| 734 InstSwitch(Cfg *Func, SizeT NumCases, Operand *Source, CfgNode *LabelDefault); | 735 InstSwitch(Cfg *Func, SizeT NumCases, Operand *Source, CfgNode *LabelDefault); |
| 735 void destroy(Cfg *Func) override { | 736 void destroy(Cfg *Func) override { |
| 736 Func->deallocateArrayOf<uint64_t>(Values); | 737 Func->deallocateArrayOf<uint64_t>(Values); |
| 737 Func->deallocateArrayOf<CfgNode *>(Labels); | 738 Func->deallocateArrayOf<CfgNode *>(Labels); |
| 738 Inst::destroy(Func); | 739 Inst::destroy(Func); |
| 739 } | 740 } |
| 740 | 741 |
| 741 CfgNode *LabelDefault; | 742 CfgNode *LabelDefault; |
| 742 SizeT NumCases; // not including the default case | 743 SizeT NumCases; /// not including the default case |
| 743 uint64_t *Values; // size is NumCases | 744 uint64_t *Values; /// size is NumCases |
| 744 CfgNode **Labels; // size is NumCases | 745 CfgNode **Labels; /// size is NumCases |
| 745 }; | 746 }; |
| 746 | 747 |
| 747 // Unreachable instruction. This is a terminator instruction with no | 748 /// Unreachable instruction. This is a terminator instruction with no |
| 748 // operands. | 749 /// operands. |
| 749 class InstUnreachable : public InstHighLevel { | 750 class InstUnreachable : public InstHighLevel { |
| 750 InstUnreachable() = delete; | 751 InstUnreachable() = delete; |
| 751 InstUnreachable(const InstUnreachable &) = delete; | 752 InstUnreachable(const InstUnreachable &) = delete; |
| 752 InstUnreachable &operator=(const InstUnreachable &) = delete; | 753 InstUnreachable &operator=(const InstUnreachable &) = delete; |
| 753 | 754 |
| 754 public: | 755 public: |
| 755 static InstUnreachable *create(Cfg *Func) { | 756 static InstUnreachable *create(Cfg *Func) { |
| 756 return new (Func->allocate<InstUnreachable>()) InstUnreachable(Func); | 757 return new (Func->allocate<InstUnreachable>()) InstUnreachable(Func); |
| 757 } | 758 } |
| 758 NodeList getTerminatorEdges() const override { return NodeList(); } | 759 NodeList getTerminatorEdges() const override { return NodeList(); } |
| 759 void dump(const Cfg *Func) const override; | 760 void dump(const Cfg *Func) const override; |
| 760 static bool classof(const Inst *Inst) { | 761 static bool classof(const Inst *Inst) { |
| 761 return Inst->getKind() == Unreachable; | 762 return Inst->getKind() == Unreachable; |
| 762 } | 763 } |
| 763 | 764 |
| 764 private: | 765 private: |
| 765 explicit InstUnreachable(Cfg *Func); | 766 explicit InstUnreachable(Cfg *Func); |
| 766 }; | 767 }; |
| 767 | 768 |
| 768 // BundleLock instruction. There are no operands. Contains an option | 769 /// BundleLock instruction. There are no operands. Contains an option |
| 769 // indicating whether align_to_end is specified. | 770 /// indicating whether align_to_end is specified. |
| 770 class InstBundleLock : public InstHighLevel { | 771 class InstBundleLock : public InstHighLevel { |
| 771 InstBundleLock() = delete; | 772 InstBundleLock() = delete; |
| 772 InstBundleLock(const InstBundleLock &) = delete; | 773 InstBundleLock(const InstBundleLock &) = delete; |
| 773 InstBundleLock &operator=(const InstBundleLock &) = delete; | 774 InstBundleLock &operator=(const InstBundleLock &) = delete; |
| 774 | 775 |
| 775 public: | 776 public: |
| 776 enum Option { Opt_None, Opt_AlignToEnd }; | 777 enum Option { Opt_None, Opt_AlignToEnd }; |
| 777 static InstBundleLock *create(Cfg *Func, Option BundleOption) { | 778 static InstBundleLock *create(Cfg *Func, Option BundleOption) { |
| 778 return new (Func->allocate<InstBundleLock>()) | 779 return new (Func->allocate<InstBundleLock>()) |
| 779 InstBundleLock(Func, BundleOption); | 780 InstBundleLock(Func, BundleOption); |
| 780 } | 781 } |
| 781 void emit(const Cfg *Func) const override; | 782 void emit(const Cfg *Func) const override; |
| 782 void emitIAS(const Cfg * /* Func */) const override {} | 783 void emitIAS(const Cfg * /* Func */) const override {} |
| 783 void dump(const Cfg *Func) const override; | 784 void dump(const Cfg *Func) const override; |
| 784 Option getOption() const { return BundleOption; } | 785 Option getOption() const { return BundleOption; } |
| 785 static bool classof(const Inst *Inst) { | 786 static bool classof(const Inst *Inst) { |
| 786 return Inst->getKind() == BundleLock; | 787 return Inst->getKind() == BundleLock; |
| 787 } | 788 } |
| 788 | 789 |
| 789 private: | 790 private: |
| 790 Option BundleOption; | 791 Option BundleOption; |
| 791 InstBundleLock(Cfg *Func, Option BundleOption); | 792 InstBundleLock(Cfg *Func, Option BundleOption); |
| 792 }; | 793 }; |
| 793 | 794 |
| 794 // BundleUnlock instruction. There are no operands. | 795 /// BundleUnlock instruction. There are no operands. |
| 795 class InstBundleUnlock : public InstHighLevel { | 796 class InstBundleUnlock : public InstHighLevel { |
| 796 InstBundleUnlock() = delete; | 797 InstBundleUnlock() = delete; |
| 797 InstBundleUnlock(const InstBundleUnlock &) = delete; | 798 InstBundleUnlock(const InstBundleUnlock &) = delete; |
| 798 InstBundleUnlock &operator=(const InstBundleUnlock &) = delete; | 799 InstBundleUnlock &operator=(const InstBundleUnlock &) = delete; |
| 799 | 800 |
| 800 public: | 801 public: |
| 801 static InstBundleUnlock *create(Cfg *Func) { | 802 static InstBundleUnlock *create(Cfg *Func) { |
| 802 return new (Func->allocate<InstBundleUnlock>()) InstBundleUnlock(Func); | 803 return new (Func->allocate<InstBundleUnlock>()) InstBundleUnlock(Func); |
| 803 } | 804 } |
| 804 void emit(const Cfg *Func) const override; | 805 void emit(const Cfg *Func) const override; |
| 805 void emitIAS(const Cfg * /* Func */) const override {} | 806 void emitIAS(const Cfg * /* Func */) const override {} |
| 806 void dump(const Cfg *Func) const override; | 807 void dump(const Cfg *Func) const override; |
| 807 static bool classof(const Inst *Inst) { | 808 static bool classof(const Inst *Inst) { |
| 808 return Inst->getKind() == BundleUnlock; | 809 return Inst->getKind() == BundleUnlock; |
| 809 } | 810 } |
| 810 | 811 |
| 811 private: | 812 private: |
| 812 explicit InstBundleUnlock(Cfg *Func); | 813 explicit InstBundleUnlock(Cfg *Func); |
| 813 }; | 814 }; |
| 814 | 815 |
| 815 // FakeDef instruction. This creates a fake definition of a variable, | 816 /// FakeDef instruction. This creates a fake definition of a variable, |
| 816 // which is how we represent the case when an instruction produces | 817 /// which is how we represent the case when an instruction produces |
| 817 // multiple results. This doesn't happen with high-level ICE | 818 /// multiple results. This doesn't happen with high-level ICE |
| 818 // instructions, but might with lowered instructions. For example, | 819 /// instructions, but might with lowered instructions. For example, |
| 819 // this would be a way to represent condition flags being modified by | 820 /// this would be a way to represent condition flags being modified by |
| 820 // an instruction. | 821 /// an instruction. |
| 821 // | 822 /// |
| 822 // It's generally useful to set the optional source operand to be the | 823 /// It's generally useful to set the optional source operand to be the |
| 823 // dest variable of the instruction that actually produces the FakeDef | 824 /// dest variable of the instruction that actually produces the FakeDef |
| 824 // dest. Otherwise, the original instruction could be dead-code | 825 /// dest. Otherwise, the original instruction could be dead-code |
| 825 // eliminated if its dest operand is unused, and therefore the FakeDef | 826 /// eliminated if its dest operand is unused, and therefore the FakeDef |
| 826 // dest wouldn't be properly initialized. | 827 /// dest wouldn't be properly initialized. |
| 827 class InstFakeDef : public InstHighLevel { | 828 class InstFakeDef : public InstHighLevel { |
| 828 InstFakeDef() = delete; | 829 InstFakeDef() = delete; |
| 829 InstFakeDef(const InstFakeDef &) = delete; | 830 InstFakeDef(const InstFakeDef &) = delete; |
| 830 InstFakeDef &operator=(const InstFakeDef &) = delete; | 831 InstFakeDef &operator=(const InstFakeDef &) = delete; |
| 831 | 832 |
| 832 public: | 833 public: |
| 833 static InstFakeDef *create(Cfg *Func, Variable *Dest, | 834 static InstFakeDef *create(Cfg *Func, Variable *Dest, |
| 834 Variable *Src = nullptr) { | 835 Variable *Src = nullptr) { |
| 835 return new (Func->allocate<InstFakeDef>()) InstFakeDef(Func, Dest, Src); | 836 return new (Func->allocate<InstFakeDef>()) InstFakeDef(Func, Dest, Src); |
| 836 } | 837 } |
| 837 void emit(const Cfg *Func) const override; | 838 void emit(const Cfg *Func) const override; |
| 838 void emitIAS(const Cfg * /* Func */) const override {} | 839 void emitIAS(const Cfg * /* Func */) const override {} |
| 839 void dump(const Cfg *Func) const override; | 840 void dump(const Cfg *Func) const override; |
| 840 static bool classof(const Inst *Inst) { return Inst->getKind() == FakeDef; } | 841 static bool classof(const Inst *Inst) { return Inst->getKind() == FakeDef; } |
| 841 | 842 |
| 842 private: | 843 private: |
| 843 InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src); | 844 InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src); |
| 844 }; | 845 }; |
| 845 | 846 |
| 846 // FakeUse instruction. This creates a fake use of a variable, to | 847 /// FakeUse instruction. This creates a fake use of a variable, to |
| 847 // keep the instruction that produces that variable from being | 848 /// keep the instruction that produces that variable from being |
| 848 // dead-code eliminated. This is useful in a variety of lowering | 849 /// dead-code eliminated. This is useful in a variety of lowering |
| 849 // situations. The FakeUse instruction has no dest, so it can itself | 850 /// situations. The FakeUse instruction has no dest, so it can itself |
| 850 // never be dead-code eliminated. | 851 /// never be dead-code eliminated. |
| 851 class InstFakeUse : public InstHighLevel { | 852 class InstFakeUse : public InstHighLevel { |
| 852 InstFakeUse() = delete; | 853 InstFakeUse() = delete; |
| 853 InstFakeUse(const InstFakeUse &) = delete; | 854 InstFakeUse(const InstFakeUse &) = delete; |
| 854 InstFakeUse &operator=(const InstFakeUse &) = delete; | 855 InstFakeUse &operator=(const InstFakeUse &) = delete; |
| 855 | 856 |
| 856 public: | 857 public: |
| 857 static InstFakeUse *create(Cfg *Func, Variable *Src) { | 858 static InstFakeUse *create(Cfg *Func, Variable *Src) { |
| 858 return new (Func->allocate<InstFakeUse>()) InstFakeUse(Func, Src); | 859 return new (Func->allocate<InstFakeUse>()) InstFakeUse(Func, Src); |
| 859 } | 860 } |
| 860 void emit(const Cfg *Func) const override; | 861 void emit(const Cfg *Func) const override; |
| 861 void emitIAS(const Cfg * /* Func */) const override {} | 862 void emitIAS(const Cfg * /* Func */) const override {} |
| 862 void dump(const Cfg *Func) const override; | 863 void dump(const Cfg *Func) const override; |
| 863 static bool classof(const Inst *Inst) { return Inst->getKind() == FakeUse; } | 864 static bool classof(const Inst *Inst) { return Inst->getKind() == FakeUse; } |
| 864 | 865 |
| 865 private: | 866 private: |
| 866 InstFakeUse(Cfg *Func, Variable *Src); | 867 InstFakeUse(Cfg *Func, Variable *Src); |
| 867 }; | 868 }; |
| 868 | 869 |
| 869 // FakeKill instruction. This "kills" a set of variables by modeling | 870 /// FakeKill instruction. This "kills" a set of variables by modeling |
| 870 // a trivial live range at this instruction for each (implicit) | 871 /// a trivial live range at this instruction for each (implicit) |
| 871 // variable. The primary use is to indicate that scratch registers | 872 /// variable. The primary use is to indicate that scratch registers |
| 872 // are killed after a call, so that the register allocator won't | 873 /// are killed after a call, so that the register allocator won't |
| 873 // assign a scratch register to a variable whose live range spans a | 874 /// assign a scratch register to a variable whose live range spans a |
| 874 // call. | 875 /// call. |
| 875 // | 876 /// |
| 876 // The FakeKill instruction also holds a pointer to the instruction | 877 /// The FakeKill instruction also holds a pointer to the instruction |
| 877 // that kills the set of variables, so that if that linked instruction | 878 /// that kills the set of variables, so that if that linked instruction |
| 878 // gets dead-code eliminated, the FakeKill instruction will as well. | 879 /// gets dead-code eliminated, the FakeKill instruction will as well. |
| 879 class InstFakeKill : public InstHighLevel { | 880 class InstFakeKill : public InstHighLevel { |
| 880 InstFakeKill() = delete; | 881 InstFakeKill() = delete; |
| 881 InstFakeKill(const InstFakeKill &) = delete; | 882 InstFakeKill(const InstFakeKill &) = delete; |
| 882 InstFakeKill &operator=(const InstFakeKill &) = delete; | 883 InstFakeKill &operator=(const InstFakeKill &) = delete; |
| 883 | 884 |
| 884 public: | 885 public: |
| 885 static InstFakeKill *create(Cfg *Func, const Inst *Linked) { | 886 static InstFakeKill *create(Cfg *Func, const Inst *Linked) { |
| 886 return new (Func->allocate<InstFakeKill>()) InstFakeKill(Func, Linked); | 887 return new (Func->allocate<InstFakeKill>()) InstFakeKill(Func, Linked); |
| 887 } | 888 } |
| 888 const Inst *getLinked() const { return Linked; } | 889 const Inst *getLinked() const { return Linked; } |
| 889 void emit(const Cfg *Func) const override; | 890 void emit(const Cfg *Func) const override; |
| 890 void emitIAS(const Cfg * /* Func */) const override {} | 891 void emitIAS(const Cfg * /* Func */) const override {} |
| 891 void dump(const Cfg *Func) const override; | 892 void dump(const Cfg *Func) const override; |
| 892 static bool classof(const Inst *Inst) { return Inst->getKind() == FakeKill; } | 893 static bool classof(const Inst *Inst) { return Inst->getKind() == FakeKill; } |
| 893 | 894 |
| 894 private: | 895 private: |
| 895 InstFakeKill(Cfg *Func, const Inst *Linked); | 896 InstFakeKill(Cfg *Func, const Inst *Linked); |
| 896 | 897 |
| 897 // This instruction is ignored if Linked->isDeleted() is true. | 898 /// This instruction is ignored if Linked->isDeleted() is true. |
| 898 const Inst *Linked; | 899 const Inst *Linked; |
| 899 }; | 900 }; |
| 900 | 901 |
| 901 // The Target instruction is the base class for all target-specific | 902 /// The Target instruction is the base class for all target-specific |
| 902 // instructions. | 903 /// instructions. |
| 903 class InstTarget : public Inst { | 904 class InstTarget : public Inst { |
| 904 InstTarget() = delete; | 905 InstTarget() = delete; |
| 905 InstTarget(const InstTarget &) = delete; | 906 InstTarget(const InstTarget &) = delete; |
| 906 InstTarget &operator=(const InstTarget &) = delete; | 907 InstTarget &operator=(const InstTarget &) = delete; |
| 907 | 908 |
| 908 public: | 909 public: |
| 909 uint32_t getEmitInstCount() const override { return 1; } | 910 uint32_t getEmitInstCount() const override { return 1; } |
| 910 void dump(const Cfg *Func) const override; | 911 void dump(const Cfg *Func) const override; |
| 911 static bool classof(const Inst *Inst) { return Inst->getKind() >= Target; } | 912 static bool classof(const Inst *Inst) { return Inst->getKind() >= Target; } |
| 912 | 913 |
| 913 protected: | 914 protected: |
| 914 InstTarget(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) | 915 InstTarget(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) |
| 915 : Inst(Func, Kind, MaxSrcs, Dest) { | 916 : Inst(Func, Kind, MaxSrcs, Dest) { |
| 916 assert(Kind >= Target); | 917 assert(Kind >= Target); |
| 917 } | 918 } |
| 918 }; | 919 }; |
| 919 | 920 |
| 920 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source); | 921 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source); |
| 921 | 922 |
| 922 } // end of namespace Ice | 923 } // end of namespace Ice |
| 923 | 924 |
| 924 namespace llvm { | 925 namespace llvm { |
| 925 | 926 |
| 926 // Override the default ilist traits so that Inst's private ctor and | 927 /// Override the default ilist traits so that Inst's private ctor and |
| 927 // deleted dtor aren't invoked. | 928 /// deleted dtor aren't invoked. |
| 928 template <> | 929 template <> |
| 929 struct ilist_traits<Ice::Inst> : public ilist_default_traits<Ice::Inst> { | 930 struct ilist_traits<Ice::Inst> : public ilist_default_traits<Ice::Inst> { |
| 930 Ice::Inst *createSentinel() const { | 931 Ice::Inst *createSentinel() const { |
| 931 return static_cast<Ice::Inst *>(&Sentinel); | 932 return static_cast<Ice::Inst *>(&Sentinel); |
| 932 } | 933 } |
| 933 static void destroySentinel(Ice::Inst *) {} | 934 static void destroySentinel(Ice::Inst *) {} |
| 934 Ice::Inst *provideInitialHead() const { return createSentinel(); } | 935 Ice::Inst *provideInitialHead() const { return createSentinel(); } |
| 935 Ice::Inst *ensureHead(Ice::Inst *) const { return createSentinel(); } | 936 Ice::Inst *ensureHead(Ice::Inst *) const { return createSentinel(); } |
| 936 static void noteHead(Ice::Inst *, Ice::Inst *) {} | 937 static void noteHead(Ice::Inst *, Ice::Inst *) {} |
| 937 void deleteNode(Ice::Inst *) {} | 938 void deleteNode(Ice::Inst *) {} |
| 938 | 939 |
| 939 private: | 940 private: |
| 940 mutable ilist_half_node<Ice::Inst> Sentinel; | 941 mutable ilist_half_node<Ice::Inst> Sentinel; |
| 941 }; | 942 }; |
| 942 | 943 |
| 943 } // end of namespace llvm | 944 } // end of namespace llvm |
| 944 | 945 |
| 945 #endif // SUBZERO_SRC_ICEINST_H | 946 #endif // SUBZERO_SRC_ICEINST_H |
| OLD | NEW |