| 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 |