Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 1 | //===- subzero/src/IceInst.h - High-level instructions ----------*- C++ -*-===// |
| 2 | // |
| 3 | // The Subzero Code Generator |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 9 | /// |
| 10 | /// \file |
Jim Stichnoth | 92a6e5b | 2015-12-02 16:52:44 -0800 | [diff] [blame] | 11 | /// \brief Declares the Inst class and its target-independent subclasses. |
| 12 | /// |
| 13 | /// These represent the high-level Vanilla ICE instructions and map roughly 1:1 |
| 14 | /// to LLVM instructions. |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 15 | /// |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 16 | //===----------------------------------------------------------------------===// |
| 17 | |
| 18 | #ifndef SUBZERO_SRC_ICEINST_H |
| 19 | #define SUBZERO_SRC_ICEINST_H |
| 20 | |
John Porto | 7e93c62 | 2015-06-23 10:58:57 -0700 | [diff] [blame] | 21 | #include "IceCfg.h" |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 22 | #include "IceDefs.h" |
| 23 | #include "IceInst.def" |
Jan Voung | 3bd9f1a | 2014-06-18 10:50:57 -0700 | [diff] [blame] | 24 | #include "IceIntrinsics.h" |
John Porto | a47c11c | 2016-04-21 05:53:42 -0700 | [diff] [blame] | 25 | #include "IceOperand.h" |
John Porto | 0307721 | 2016-04-05 06:30:21 -0700 | [diff] [blame] | 26 | #include "IceSwitchLowering.h" |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 27 | #include "IceTypes.h" |
| 28 | |
| 29 | // TODO: The Cfg structure, and instructions in particular, need to be |
Andrew Scull | 6ef7949 | 2015-09-09 15:50:42 -0700 | [diff] [blame] | 30 | // validated for things like valid operand types, valid branch targets, proper |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 31 | // ordering of Phi and non-Phi instructions, etc. Most of the validity checking |
| 32 | // will be done in the bitcode reader. We need a list of everything that should |
| 33 | // be validated, and tests for each. |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 34 | |
| 35 | namespace Ice { |
| 36 | |
Andrew Scull | 6ef7949 | 2015-09-09 15:50:42 -0700 | [diff] [blame] | 37 | /// Base instruction class for ICE. Inst has two subclasses: InstHighLevel and |
| 38 | /// InstTarget. High-level ICE instructions inherit from InstHighLevel, and |
| 39 | /// low-level (target-specific) ICE instructions inherit from InstTarget. |
Jim Stichnoth | 607e9f0 | 2014-11-06 13:32:05 -0800 | [diff] [blame] | 40 | class Inst : public llvm::ilist_node<Inst> { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 41 | Inst() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 42 | Inst(const Inst &) = delete; |
| 43 | Inst &operator=(const Inst &) = delete; |
| 44 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 45 | public: |
| 46 | enum InstKind { |
| 47 | // Arbitrary (alphabetical) order, except put Unreachable first. |
| 48 | Unreachable, |
| 49 | Alloca, |
| 50 | Arithmetic, |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 51 | Br, |
| 52 | Call, |
| 53 | Cast, |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 54 | ExtractElement, |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 55 | Fcmp, |
| 56 | Icmp, |
Jan Voung | 3bd9f1a | 2014-06-18 10:50:57 -0700 | [diff] [blame] | 57 | IntrinsicCall, |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 58 | InsertElement, |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 59 | Load, |
| 60 | Phi, |
| 61 | Ret, |
| 62 | Select, |
| 63 | Store, |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 64 | Switch, |
John Porto | a47c11c | 2016-04-21 05:53:42 -0700 | [diff] [blame] | 65 | Assign, // not part of LLVM/PNaCl bitcode |
| 66 | Breakpoint, // not part of LLVM/PNaCl bitcode |
| 67 | BundleLock, // not part of LLVM/PNaCl bitcode |
| 68 | BundleUnlock, // not part of LLVM/PNaCl bitcode |
| 69 | FakeDef, // not part of LLVM/PNaCl bitcode |
| 70 | FakeUse, // not part of LLVM/PNaCl bitcode |
| 71 | FakeKill, // not part of LLVM/PNaCl bitcode |
| 72 | JumpTable, // not part of LLVM/PNaCl bitcode |
| 73 | ShuffleVector, // not part of LLVM/PNaCl bitcode |
Andrew Scull | 6ef7949 | 2015-09-09 15:50:42 -0700 | [diff] [blame] | 74 | // Anything >= Target is an InstTarget subclass. Note that the value-spaces |
| 75 | // are shared across targets. To avoid confusion over the definition of |
| 76 | // shared values, an object specific to one target should never be passed |
| 77 | // to a different target. |
| 78 | Target, |
| 79 | Target_Max = std::numeric_limits<uint8_t>::max(), |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 80 | }; |
Andrew Scull | 6ef7949 | 2015-09-09 15:50:42 -0700 | [diff] [blame] | 81 | static_assert(Target <= Target_Max, "Must not be above max."); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 82 | InstKind getKind() const { return Kind; } |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 83 | virtual const char *getInstName() const; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 84 | |
Jim Stichnoth | d97c7df | 2014-06-04 11:57:08 -0700 | [diff] [blame] | 85 | InstNumberT getNumber() const { return Number; } |
| 86 | void renumber(Cfg *Func); |
Jim Stichnoth | e5b73e6 | 2014-12-15 09:58:51 -0800 | [diff] [blame] | 87 | enum { |
| 88 | NumberDeleted = -1, |
| 89 | NumberSentinel = 0, |
| 90 | NumberInitial = 2, |
| 91 | NumberExtended = NumberInitial - 1 |
| 92 | }; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 93 | |
| 94 | bool isDeleted() const { return Deleted; } |
| 95 | void setDeleted() { Deleted = true; } |
Jim Stichnoth | a59ae6f | 2015-05-17 10:11:41 -0700 | [diff] [blame] | 96 | void setDead(bool Value = true) { Dead = Value; } |
Jim Stichnoth | d97c7df | 2014-06-04 11:57:08 -0700 | [diff] [blame] | 97 | void deleteIfDead(); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 98 | |
| 99 | bool hasSideEffects() const { return HasSideEffects; } |
| 100 | |
Jim Stichnoth | 230d410 | 2015-09-25 17:40:32 -0700 | [diff] [blame] | 101 | bool isDestRedefined() const { return IsDestRedefined; } |
| 102 | void setDestRedefined() { IsDestRedefined = true; } |
Jim Stichnoth | 4775255 | 2014-10-13 17:15:08 -0700 | [diff] [blame] | 103 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 104 | Variable *getDest() const { return Dest; } |
| 105 | |
Manasij Mukherjee | 45f51a2 | 2016-06-27 16:12:37 -0700 | [diff] [blame] | 106 | SizeT getSrcSize() const { return Srcs.size(); } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 107 | Operand *getSrc(SizeT I) const { |
| 108 | assert(I < getSrcSize()); |
| 109 | return Srcs[I]; |
| 110 | } |
Manasij Mukherjee | 032c315 | 2016-05-24 14:25:04 -0700 | [diff] [blame] | 111 | void replaceSource(SizeT Index, Operand *Replacement) { |
Manasij Mukherjee | 45f51a2 | 2016-06-27 16:12:37 -0700 | [diff] [blame] | 112 | assert(Index < getSrcSize()); |
Manasij Mukherjee | 032c315 | 2016-05-24 14:25:04 -0700 | [diff] [blame] | 113 | assert(!isDeleted()); |
Manasij Mukherjee | 032c315 | 2016-05-24 14:25:04 -0700 | [diff] [blame] | 114 | Srcs[Index] = Replacement; |
| 115 | } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 116 | |
Jim Stichnoth | d97c7df | 2014-06-04 11:57:08 -0700 | [diff] [blame] | 117 | bool isLastUse(const Operand *Src) const; |
Jim Stichnoth | 8e6bf6e | 2015-06-03 15:58:12 -0700 | [diff] [blame] | 118 | void spliceLivenessInfo(Inst *OrigInst, Inst *SpliceAssn); |
Jim Stichnoth | d97c7df | 2014-06-04 11:57:08 -0700 | [diff] [blame] | 119 | |
Andrew Scull | 6ef7949 | 2015-09-09 15:50:42 -0700 | [diff] [blame] | 120 | /// Returns a list of out-edges corresponding to a terminator instruction, |
| 121 | /// which is the last instruction of the block. The list must not contain |
| 122 | /// duplicates. |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 123 | virtual NodeList getTerminatorEdges() const { |
Andrew Scull | 6ef7949 | 2015-09-09 15:50:42 -0700 | [diff] [blame] | 124 | // All valid terminator instructions override this method. For the default |
| 125 | // implementation, we assert in case some CfgNode is constructed without a |
| 126 | // terminator instruction at the end. |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 127 | llvm_unreachable( |
| 128 | "getTerminatorEdges() called on a non-terminator instruction"); |
| 129 | return NodeList(); |
| 130 | } |
Jim Stichnoth | 336f6c4 | 2014-10-30 15:01:31 -0700 | [diff] [blame] | 131 | virtual bool isUnconditionalBranch() const { return false; } |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 132 | /// If the instruction is a branch-type instruction with OldNode as a target, |
| 133 | /// repoint it to NewNode and return true, otherwise return false. Repoint all |
| 134 | /// instances of OldNode as a target. |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 135 | virtual bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) { |
Jim Stichnoth | 336f6c4 | 2014-10-30 15:01:31 -0700 | [diff] [blame] | 136 | (void)OldNode; |
| 137 | (void)NewNode; |
| 138 | return false; |
| 139 | } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 140 | |
Jim Stichnoth | 28b71be | 2015-10-12 15:24:46 -0700 | [diff] [blame] | 141 | /// Returns true if the instruction is equivalent to a simple |
| 142 | /// "var_dest=var_src" assignment where the dest and src are both variables. |
| 143 | virtual bool isVarAssign() const { return false; } |
Jim Stichnoth | ad40353 | 2014-09-25 12:44:17 -0700 | [diff] [blame] | 144 | |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 145 | /// Returns true if the instruction has a possible side effect of changing |
| 146 | /// memory, in which case a memory load should not be reordered with respect |
| 147 | /// to this instruction. It should really be pure virtual, but we can't |
| 148 | /// because of g++ and llvm::ilist<>, so we implement it as |
| 149 | /// report_fatal_error(). |
| 150 | virtual bool isMemoryWrite() const; |
| 151 | |
Jim Stichnoth | b9a8472 | 2016-08-01 13:18:36 -0700 | [diff] [blame] | 152 | /// Returns true if the (target-specific) instruction represents an |
| 153 | /// intra-block label, i.e. branch target. This is meant primarily for |
| 154 | /// Cfg::splitLocalVars(). |
| 155 | virtual bool isLabel() const { return false; } |
| 156 | /// If the (target-specific) instruction represents an intra-block branch to |
| 157 | /// some Label instruction, return that Label branch target instruction; |
| 158 | /// otherwise return nullptr. |
| 159 | virtual const Inst *getIntraBlockBranchTarget() const { return nullptr; } |
| 160 | |
Jim Stichnoth | 4775255 | 2014-10-13 17:15:08 -0700 | [diff] [blame] | 161 | void livenessLightweight(Cfg *Func, LivenessBV &Live); |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 162 | /// Calculates liveness for this instruction. Returns true if this instruction |
| 163 | /// is (tentatively) still live and should be retained, and false if this |
| 164 | /// instruction is (tentatively) dead and should be deleted. The decision is |
| 165 | /// tentative until the liveness dataflow algorithm has converged, and then a |
| 166 | /// separate pass permanently deletes dead instructions. |
Jim Stichnoth | 336f6c4 | 2014-10-30 15:01:31 -0700 | [diff] [blame] | 167 | bool liveness(InstNumberT InstNumber, LivenessBV &Live, Liveness *Liveness, |
Jim Stichnoth | 4775255 | 2014-10-13 17:15:08 -0700 | [diff] [blame] | 168 | LiveBeginEndMap *LiveBegin, LiveBeginEndMap *LiveEnd); |
Jim Stichnoth | 1873560 | 2014-09-16 19:59:35 -0700 | [diff] [blame] | 169 | |
Andrew Scull | 6ef7949 | 2015-09-09 15:50:42 -0700 | [diff] [blame] | 170 | /// Get the number of native instructions that this instruction ultimately |
| 171 | /// emits. By default, high-level instructions don't result in any native |
| 172 | /// instructions, and a target-specific instruction results in a single native |
| 173 | /// instruction. |
Jim Stichnoth | 1873560 | 2014-09-16 19:59:35 -0700 | [diff] [blame] | 174 | virtual uint32_t getEmitInstCount() const { return 0; } |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 175 | // TODO(stichnot): Change Inst back to abstract once the g++ build issue is |
| 176 | // fixed. llvm::ilist<Ice::Inst> doesn't work under g++ because the |
| 177 | // resize(size_t, Ice::Inst) method is incorrectly declared and thus doesn't |
| 178 | // allow the abstract class Ice::Inst. The method should be declared |
| 179 | // resize(size_t, const Ice::Inst &). virtual void emit(const Cfg *Func) |
| 180 | // const = 0; virtual void emitIAS(const Cfg *Func) const = 0; |
Jim Stichnoth | dddaf9c | 2014-12-04 14:09:21 -0800 | [diff] [blame] | 181 | virtual void emit(const Cfg *) const { |
| 182 | llvm_unreachable("emit on abstract class"); |
| 183 | } |
| 184 | virtual void emitIAS(const Cfg *Func) const { emit(Func); } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 185 | virtual void dump(const Cfg *Func) const; |
Jim Stichnoth | d97c7df | 2014-06-04 11:57:08 -0700 | [diff] [blame] | 186 | virtual void dumpExtras(const Cfg *Func) const; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 187 | void dumpDecorated(const Cfg *Func) const; |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 188 | void emitSources(const Cfg *Func) const; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 189 | void dumpSources(const Cfg *Func) const; |
| 190 | void dumpDest(const Cfg *Func) const; |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 191 | virtual bool isRedundantAssign() const { return false; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 192 | |
Sean Klein | fc707ff | 2016-02-29 16:44:07 -0800 | [diff] [blame] | 193 | virtual ~Inst() = default; |
Manasij Mukherjee | 7cd926d | 2016-08-04 12:33:23 -0700 | [diff] [blame] | 194 | void replaceDest(Variable *Var) { Dest = Var; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 195 | |
Nicolas Capens | 038a9b9 | 2016-09-12 15:40:25 -0400 | [diff] [blame] | 196 | void operator delete(void *Ptr, std::size_t Size) { |
| 197 | assert(CfgAllocatorTraits::current() != nullptr); |
| 198 | CfgAllocatorTraits::current()->Deallocate(Ptr, Size); |
| 199 | llvm::report_fatal_error("Inst unexpectedly deleted"); |
| 200 | } |
| 201 | |
Alexis Hetu | 932640b | 2018-06-20 15:35:53 -0400 | [diff] [blame] | 202 | inline void* getExternalData() const { return externalData; } |
| 203 | inline void setExternalData(void* data) { externalData = data; } |
| 204 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 205 | protected: |
| 206 | Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest); |
| 207 | void addSource(Operand *Src) { |
| 208 | assert(Src); |
Manasij Mukherjee | 45f51a2 | 2016-06-27 16:12:37 -0700 | [diff] [blame] | 209 | Srcs.push_back(Src); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 210 | } |
Jim Stichnoth | d97c7df | 2014-06-04 11:57:08 -0700 | [diff] [blame] | 211 | void setLastUse(SizeT VarIndex) { |
| 212 | if (VarIndex < CHAR_BIT * sizeof(LiveRangesEnded)) |
| 213 | LiveRangesEnded |= (((LREndedBits)1u) << VarIndex); |
| 214 | } |
| 215 | void resetLastUses() { LiveRangesEnded = 0; } |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 216 | /// The destroy() method lets the instruction cleanly release any memory that |
| 217 | /// was allocated via the Cfg's allocator. |
Manasij Mukherjee | 45f51a2 | 2016-06-27 16:12:37 -0700 | [diff] [blame] | 218 | virtual void destroy(Cfg *) {} |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 219 | |
| 220 | const InstKind Kind; |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 221 | /// Number is the instruction number for describing live ranges. |
Jim Stichnoth | d97c7df | 2014-06-04 11:57:08 -0700 | [diff] [blame] | 222 | InstNumberT Number; |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 223 | /// Deleted means irrevocably deleted. |
Jim Stichnoth | eafb56c | 2015-06-22 10:35:22 -0700 | [diff] [blame] | 224 | bool Deleted = false; |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 225 | /// Dead means one of two things depending on context: (1) pending deletion |
| 226 | /// after liveness analysis converges, or (2) marked for deletion during |
| 227 | /// lowering due to a folded bool operation. |
Jim Stichnoth | eafb56c | 2015-06-22 10:35:22 -0700 | [diff] [blame] | 228 | bool Dead = false; |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 229 | /// HasSideEffects means the instruction is something like a function call or |
| 230 | /// a volatile load that can't be removed even if its Dest variable is not |
| 231 | /// live. |
Jim Stichnoth | eafb56c | 2015-06-22 10:35:22 -0700 | [diff] [blame] | 232 | bool HasSideEffects = false; |
Jim Stichnoth | 230d410 | 2015-09-25 17:40:32 -0700 | [diff] [blame] | 233 | /// IsDestRedefined indicates that this instruction is not the first |
| 234 | /// definition of Dest in the basic block. The effect is that liveness |
| 235 | /// analysis shouldn't consider this instruction to be the start of Dest's |
| 236 | /// live range; rather, there is some other instruction earlier in the basic |
| 237 | /// block with the same Dest. This is maintained because liveness analysis |
| 238 | /// has an invariant (primarily for performance reasons) that any Variable's |
| 239 | /// live range recorded in a basic block has at most one start and at most one |
| 240 | /// end. |
| 241 | bool IsDestRedefined = false; |
Alexis Hetu | 932640b | 2018-06-20 15:35:53 -0400 | [diff] [blame] | 242 | /// External data can be set by an optimizer to compute and retain any |
| 243 | /// information related to the current instruction. All the memory used to |
| 244 | /// store this information must be managed by the optimizer. |
| 245 | void* externalData = nullptr; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 246 | |
| 247 | Variable *Dest; |
| 248 | const SizeT MaxSrcs; // only used for assert |
Manasij Mukherjee | 45f51a2 | 2016-06-27 16:12:37 -0700 | [diff] [blame] | 249 | |
| 250 | CfgVector<Operand *> Srcs; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 251 | |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 252 | /// LiveRangesEnded marks which Variables' live ranges end in this |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 253 | /// instruction. An instruction can have an arbitrary number of source |
| 254 | /// operands (e.g. a call instruction), and each source operand can contain 0 |
| 255 | /// or 1 Variable (and target-specific operands could contain more than 1 |
| 256 | /// Variable). All the variables in an instruction are conceptually flattened |
| 257 | /// and each variable is mapped to one bit position of the LiveRangesEnded bit |
| 258 | /// vector. Only the first CHAR_BIT * sizeof(LREndedBits) variables are |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 259 | /// tracked this way. |
Andrew Scull | 8072bae | 2015-09-14 16:01:26 -0700 | [diff] [blame] | 260 | using LREndedBits = uint32_t; // only first 32 src operands tracked, sorry |
Jim Stichnoth | d97c7df | 2014-06-04 11:57:08 -0700 | [diff] [blame] | 261 | LREndedBits LiveRangesEnded; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 262 | }; |
| 263 | |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 264 | class InstHighLevel : public Inst { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 265 | InstHighLevel() = delete; |
Jim Stichnoth | 0795ba0 | 2014-10-01 14:23:01 -0700 | [diff] [blame] | 266 | InstHighLevel(const InstHighLevel &) = delete; |
| 267 | InstHighLevel &operator=(const InstHighLevel &) = delete; |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 268 | |
| 269 | protected: |
| 270 | InstHighLevel(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) |
| 271 | : Inst(Func, Kind, MaxSrcs, Dest) {} |
| 272 | void emit(const Cfg * /*Func*/) const override { |
| 273 | llvm_unreachable("emit() called on a non-lowered instruction"); |
| 274 | } |
| 275 | void emitIAS(const Cfg * /*Func*/) const override { |
| 276 | llvm_unreachable("emitIAS() called on a non-lowered instruction"); |
| 277 | } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 278 | }; |
| 279 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 280 | /// Alloca instruction. This captures the size in bytes as getSrc(0), and the |
| 281 | /// required alignment in bytes. The alignment must be either 0 (no alignment |
| 282 | /// required) or a power of 2. |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 283 | class InstAlloca : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 284 | InstAlloca() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 285 | InstAlloca(const InstAlloca &) = delete; |
| 286 | InstAlloca &operator=(const InstAlloca &) = delete; |
| 287 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 288 | public: |
David Sehr | 2f3b8ec | 2015-11-16 16:51:39 -0800 | [diff] [blame] | 289 | static InstAlloca *create(Cfg *Func, Variable *Dest, Operand *ByteCount, |
| 290 | uint32_t AlignInBytes) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 291 | return new (Func->allocate<InstAlloca>()) |
David Sehr | 2f3b8ec | 2015-11-16 16:51:39 -0800 | [diff] [blame] | 292 | InstAlloca(Func, Dest, ByteCount, AlignInBytes); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 293 | } |
| 294 | uint32_t getAlignInBytes() const { return AlignInBytes; } |
| 295 | Operand *getSizeInBytes() const { return getSrc(0); } |
Jim Stichnoth | 55f931f | 2015-09-23 16:33:08 -0700 | [diff] [blame] | 296 | bool getKnownFrameOffset() const { return KnownFrameOffset; } |
| 297 | void setKnownFrameOffset() { KnownFrameOffset = true; } |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 298 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 299 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 300 | static bool classof(const Inst *Instr) { return Instr->getKind() == Alloca; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 301 | |
| 302 | private: |
David Sehr | 2f3b8ec | 2015-11-16 16:51:39 -0800 | [diff] [blame] | 303 | InstAlloca(Cfg *Func, Variable *Dest, Operand *ByteCount, |
| 304 | uint32_t AlignInBytes); |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 305 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 306 | const uint32_t AlignInBytes; |
Jim Stichnoth | 55f931f | 2015-09-23 16:33:08 -0700 | [diff] [blame] | 307 | bool KnownFrameOffset = false; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 308 | }; |
| 309 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 310 | /// Binary arithmetic instruction. The source operands are captured in getSrc(0) |
| 311 | /// and getSrc(1). |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 312 | class InstArithmetic : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 313 | InstArithmetic() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 314 | InstArithmetic(const InstArithmetic &) = delete; |
| 315 | InstArithmetic &operator=(const InstArithmetic &) = delete; |
| 316 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 317 | public: |
| 318 | enum OpKind { |
| 319 | #define X(tag, str, commutative) tag, |
| 320 | ICEINSTARITHMETIC_TABLE |
| 321 | #undef X |
Jim Stichnoth | 4376d29 | 2014-05-23 13:39:02 -0700 | [diff] [blame] | 322 | _num |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 323 | }; |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 324 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 325 | static InstArithmetic *create(Cfg *Func, OpKind Op, Variable *Dest, |
| 326 | Operand *Source1, Operand *Source2) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 327 | return new (Func->allocate<InstArithmetic>()) |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 328 | InstArithmetic(Func, Op, Dest, Source1, Source2); |
| 329 | } |
| 330 | OpKind getOp() const { return Op; } |
Eric Holk | e37076a | 2016-01-27 14:06:35 -0800 | [diff] [blame] | 331 | |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 332 | virtual const char *getInstName() const override; |
Eric Holk | e37076a | 2016-01-27 14:06:35 -0800 | [diff] [blame] | 333 | |
Karl Schimpf | d6064a1 | 2014-08-27 15:34:58 -0700 | [diff] [blame] | 334 | static const char *getOpName(OpKind Op); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 335 | bool isCommutative() const; |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 336 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 337 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 338 | static bool classof(const Inst *Instr) { |
| 339 | return Instr->getKind() == Arithmetic; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 340 | } |
| 341 | |
| 342 | private: |
| 343 | InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, Operand *Source1, |
| 344 | Operand *Source2); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 345 | |
| 346 | const OpKind Op; |
| 347 | }; |
| 348 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 349 | /// Assignment instruction. The source operand is captured in getSrc(0). This is |
| 350 | /// not part of the LLVM bitcode, but is a useful abstraction for some of the |
| 351 | /// lowering. E.g., if Phi instruction lowering happens before target lowering, |
| 352 | /// or for representing an Inttoptr instruction, or as an intermediate step for |
| 353 | /// lowering a Load instruction. |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 354 | class InstAssign : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 355 | InstAssign() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 356 | InstAssign(const InstAssign &) = delete; |
| 357 | InstAssign &operator=(const InstAssign &) = delete; |
| 358 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 359 | public: |
| 360 | static InstAssign *create(Cfg *Func, Variable *Dest, Operand *Source) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 361 | return new (Func->allocate<InstAssign>()) InstAssign(Func, Dest, Source); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 362 | } |
Jim Stichnoth | 28b71be | 2015-10-12 15:24:46 -0700 | [diff] [blame] | 363 | bool isVarAssign() const override; |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 364 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 365 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 366 | static bool classof(const Inst *Instr) { return Instr->getKind() == Assign; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 367 | |
| 368 | private: |
| 369 | InstAssign(Cfg *Func, Variable *Dest, Operand *Source); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 370 | }; |
| 371 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 372 | /// Branch instruction. This represents both conditional and unconditional |
| 373 | /// branches. |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 374 | class InstBr : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 375 | InstBr() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 376 | InstBr(const InstBr &) = delete; |
| 377 | InstBr &operator=(const InstBr &) = delete; |
| 378 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 379 | public: |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 380 | /// Create a conditional branch. If TargetTrue==TargetFalse, it is optimized |
| 381 | /// to an unconditional branch. |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 382 | static InstBr *create(Cfg *Func, Operand *Source, CfgNode *TargetTrue, |
| 383 | CfgNode *TargetFalse) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 384 | return new (Func->allocate<InstBr>()) |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 385 | InstBr(Func, Source, TargetTrue, TargetFalse); |
| 386 | } |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 387 | /// Create an unconditional branch. |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 388 | static InstBr *create(Cfg *Func, CfgNode *Target) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 389 | return new (Func->allocate<InstBr>()) InstBr(Func, Target); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 390 | } |
Jim Stichnoth | ae95320 | 2014-12-20 06:17:49 -0800 | [diff] [blame] | 391 | bool isUnconditional() const { return getTargetTrue() == nullptr; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 392 | Operand *getCondition() const { |
| 393 | assert(!isUnconditional()); |
| 394 | return getSrc(0); |
| 395 | } |
| 396 | CfgNode *getTargetTrue() const { return TargetTrue; } |
| 397 | CfgNode *getTargetFalse() const { return TargetFalse; } |
| 398 | CfgNode *getTargetUnconditional() const { |
| 399 | assert(isUnconditional()); |
| 400 | return getTargetFalse(); |
| 401 | } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 402 | NodeList getTerminatorEdges() const override; |
Jim Stichnoth | 336f6c4 | 2014-10-30 15:01:31 -0700 | [diff] [blame] | 403 | bool isUnconditionalBranch() const override { return isUnconditional(); } |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 404 | bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override; |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 405 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 406 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 407 | static bool classof(const Inst *Instr) { return Instr->getKind() == Br; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 408 | |
| 409 | private: |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 410 | /// Conditional branch |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 411 | InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, CfgNode *TargetFalse); |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 412 | /// Unconditional branch |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 413 | InstBr(Cfg *Func, CfgNode *Target); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 414 | |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 415 | CfgNode *TargetFalse; /// Doubles as unconditional branch target |
| 416 | CfgNode *TargetTrue; /// nullptr if unconditional branch |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 417 | }; |
| 418 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 419 | /// Call instruction. The call target is captured as getSrc(0), and arg I is |
| 420 | /// captured as getSrc(I+1). |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 421 | class InstCall : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 422 | InstCall() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 423 | InstCall(const InstCall &) = delete; |
| 424 | InstCall &operator=(const InstCall &) = delete; |
| 425 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 426 | public: |
| 427 | static InstCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest, |
John Porto | 5e0a8a7 | 2015-11-20 13:50:36 -0800 | [diff] [blame] | 428 | Operand *CallTarget, bool HasTailCall, |
| 429 | bool IsTargetHelperCall = false) { |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 430 | /// Set HasSideEffects to true so that the call instruction can't be |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 431 | /// dead-code eliminated. IntrinsicCalls can override this if the particular |
| 432 | /// intrinsic is deletable and has no side-effects. |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 433 | constexpr bool HasSideEffects = true; |
| 434 | constexpr InstKind Kind = Inst::Call; |
John Porto | 5e0a8a7 | 2015-11-20 13:50:36 -0800 | [diff] [blame] | 435 | return new (Func->allocate<InstCall>()) |
| 436 | InstCall(Func, NumArgs, Dest, CallTarget, HasTailCall, |
| 437 | IsTargetHelperCall, HasSideEffects, Kind); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 438 | } |
| 439 | void addArg(Operand *Arg) { addSource(Arg); } |
| 440 | Operand *getCallTarget() const { return getSrc(0); } |
| 441 | Operand *getArg(SizeT I) const { return getSrc(I + 1); } |
| 442 | SizeT getNumArgs() const { return getSrcSize() - 1; } |
Karl Schimpf | 8df26f3 | 2014-09-19 09:33:26 -0700 | [diff] [blame] | 443 | bool isTailcall() const { return HasTailCall; } |
John Porto | 5e0a8a7 | 2015-11-20 13:50:36 -0800 | [diff] [blame] | 444 | bool isTargetHelperCall() const { return IsTargetHelperCall; } |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 445 | bool isMemoryWrite() const override { return true; } |
Jan Voung | 3ce1a99 | 2015-02-03 08:27:44 -0800 | [diff] [blame] | 446 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 447 | static bool classof(const Inst *Instr) { return Instr->getKind() == Call; } |
Karl Schimpf | 8df26f3 | 2014-09-19 09:33:26 -0700 | [diff] [blame] | 448 | Type getReturnType() const; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 449 | |
Jan Voung | 3bd9f1a | 2014-06-18 10:50:57 -0700 | [diff] [blame] | 450 | protected: |
| 451 | InstCall(Cfg *Func, SizeT NumArgs, Variable *Dest, Operand *CallTarget, |
John Porto | 5e0a8a7 | 2015-11-20 13:50:36 -0800 | [diff] [blame] | 452 | bool HasTailCall, bool IsTargetHelperCall, bool HasSideEff, |
| 453 | InstKind Kind) |
| 454 | : InstHighLevel(Func, Kind, NumArgs + 1, Dest), HasTailCall(HasTailCall), |
| 455 | IsTargetHelperCall(IsTargetHelperCall) { |
Jan Voung | 3bd9f1a | 2014-06-18 10:50:57 -0700 | [diff] [blame] | 456 | HasSideEffects = HasSideEff; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 457 | addSource(CallTarget); |
| 458 | } |
Jan Voung | 3bd9f1a | 2014-06-18 10:50:57 -0700 | [diff] [blame] | 459 | |
| 460 | private: |
John Porto | 5e0a8a7 | 2015-11-20 13:50:36 -0800 | [diff] [blame] | 461 | const bool HasTailCall; |
| 462 | const bool IsTargetHelperCall; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 463 | }; |
| 464 | |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 465 | /// Cast instruction (a.k.a. conversion operation). |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 466 | class InstCast : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 467 | InstCast() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 468 | InstCast(const InstCast &) = delete; |
| 469 | InstCast &operator=(const InstCast &) = delete; |
| 470 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 471 | public: |
| 472 | enum OpKind { |
| 473 | #define X(tag, str) tag, |
| 474 | ICEINSTCAST_TABLE |
| 475 | #undef X |
Jim Stichnoth | 4376d29 | 2014-05-23 13:39:02 -0700 | [diff] [blame] | 476 | _num |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 477 | }; |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 478 | |
Karl Schimpf | bf17037 | 2014-12-15 10:16:31 -0800 | [diff] [blame] | 479 | static const char *getCastName(OpKind Kind); |
| 480 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 481 | static InstCast *create(Cfg *Func, OpKind CastKind, Variable *Dest, |
| 482 | Operand *Source) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 483 | return new (Func->allocate<InstCast>()) |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 484 | InstCast(Func, CastKind, Dest, Source); |
| 485 | } |
| 486 | OpKind getCastKind() const { return CastKind; } |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 487 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 488 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 489 | static bool classof(const Inst *Instr) { return Instr->getKind() == Cast; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 490 | |
| 491 | private: |
| 492 | InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source); |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 493 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 494 | const OpKind CastKind; |
| 495 | }; |
| 496 | |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 497 | /// ExtractElement instruction. |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 498 | class InstExtractElement : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 499 | InstExtractElement() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 500 | InstExtractElement(const InstExtractElement &) = delete; |
| 501 | InstExtractElement &operator=(const InstExtractElement &) = delete; |
| 502 | |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 503 | public: |
| 504 | static InstExtractElement *create(Cfg *Func, Variable *Dest, Operand *Source1, |
| 505 | Operand *Source2) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 506 | return new (Func->allocate<InstExtractElement>()) |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 507 | InstExtractElement(Func, Dest, Source1, Source2); |
| 508 | } |
| 509 | |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 510 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 511 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 512 | static bool classof(const Inst *Instr) { |
| 513 | return Instr->getKind() == ExtractElement; |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 514 | } |
| 515 | |
| 516 | private: |
| 517 | InstExtractElement(Cfg *Func, Variable *Dest, Operand *Source1, |
| 518 | Operand *Source2); |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 519 | }; |
| 520 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 521 | /// Floating-point comparison instruction. The source operands are captured in |
| 522 | /// getSrc(0) and getSrc(1). |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 523 | class InstFcmp : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 524 | InstFcmp() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 525 | InstFcmp(const InstFcmp &) = delete; |
| 526 | InstFcmp &operator=(const InstFcmp &) = delete; |
| 527 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 528 | public: |
| 529 | enum FCond { |
| 530 | #define X(tag, str) tag, |
| 531 | ICEINSTFCMP_TABLE |
| 532 | #undef X |
Jim Stichnoth | 4376d29 | 2014-05-23 13:39:02 -0700 | [diff] [blame] | 533 | _num |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 534 | }; |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 535 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 536 | static InstFcmp *create(Cfg *Func, FCond Condition, Variable *Dest, |
| 537 | Operand *Source1, Operand *Source2) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 538 | return new (Func->allocate<InstFcmp>()) |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 539 | InstFcmp(Func, Condition, Dest, Source1, Source2); |
| 540 | } |
| 541 | FCond getCondition() const { return Condition; } |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 542 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 543 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 544 | static bool classof(const Inst *Instr) { return Instr->getKind() == Fcmp; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 545 | |
| 546 | private: |
| 547 | InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1, |
| 548 | Operand *Source2); |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 549 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 550 | const FCond Condition; |
| 551 | }; |
| 552 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 553 | /// Integer comparison instruction. The source operands are captured in |
| 554 | /// getSrc(0) and getSrc(1). |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 555 | class InstIcmp : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 556 | InstIcmp() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 557 | InstIcmp(const InstIcmp &) = delete; |
| 558 | InstIcmp &operator=(const InstIcmp &) = delete; |
| 559 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 560 | public: |
| 561 | enum ICond { |
Manasij Mukherjee | 0c70417 | 2016-07-21 12:40:24 -0700 | [diff] [blame] | 562 | #define X(tag, inverse, str) tag, |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 563 | ICEINSTICMP_TABLE |
| 564 | #undef X |
Jim Stichnoth | 4376d29 | 2014-05-23 13:39:02 -0700 | [diff] [blame] | 565 | _num |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 566 | }; |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 567 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 568 | static InstIcmp *create(Cfg *Func, ICond Condition, Variable *Dest, |
| 569 | Operand *Source1, Operand *Source2) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 570 | return new (Func->allocate<InstIcmp>()) |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 571 | InstIcmp(Func, Condition, Dest, Source1, Source2); |
| 572 | } |
| 573 | ICond getCondition() const { return Condition; } |
Manasij Mukherjee | 0c70417 | 2016-07-21 12:40:24 -0700 | [diff] [blame] | 574 | void reverseConditionAndOperands(); |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 575 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 576 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 577 | static bool classof(const Inst *Instr) { return Instr->getKind() == Icmp; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 578 | |
| 579 | private: |
| 580 | InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1, |
| 581 | Operand *Source2); |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 582 | |
Manasij Mukherjee | 0c70417 | 2016-07-21 12:40:24 -0700 | [diff] [blame] | 583 | ICond Condition; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 584 | }; |
| 585 | |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 586 | /// InsertElement instruction. |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 587 | class InstInsertElement : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 588 | InstInsertElement() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 589 | InstInsertElement(const InstInsertElement &) = delete; |
| 590 | InstInsertElement &operator=(const InstInsertElement &) = delete; |
| 591 | |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 592 | public: |
| 593 | static InstInsertElement *create(Cfg *Func, Variable *Dest, Operand *Source1, |
| 594 | Operand *Source2, Operand *Source3) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 595 | return new (Func->allocate<InstInsertElement>()) |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 596 | InstInsertElement(Func, Dest, Source1, Source2, Source3); |
| 597 | } |
| 598 | |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 599 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 600 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 601 | static bool classof(const Inst *Instr) { |
| 602 | return Instr->getKind() == InsertElement; |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 603 | } |
| 604 | |
| 605 | private: |
| 606 | InstInsertElement(Cfg *Func, Variable *Dest, Operand *Source1, |
| 607 | Operand *Source2, Operand *Source3); |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 608 | }; |
| 609 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 610 | /// Call to an intrinsic function. The call target is captured as getSrc(0), and |
| 611 | /// arg I is captured as getSrc(I+1). |
Jan Voung | 3bd9f1a | 2014-06-18 10:50:57 -0700 | [diff] [blame] | 612 | class InstIntrinsicCall : public InstCall { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 613 | InstIntrinsicCall() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 614 | InstIntrinsicCall(const InstIntrinsicCall &) = delete; |
| 615 | InstIntrinsicCall &operator=(const InstIntrinsicCall &) = delete; |
| 616 | |
Jan Voung | 3bd9f1a | 2014-06-18 10:50:57 -0700 | [diff] [blame] | 617 | public: |
| 618 | static InstIntrinsicCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest, |
| 619 | Operand *CallTarget, |
| 620 | const Intrinsics::IntrinsicInfo &Info) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 621 | return new (Func->allocate<InstIntrinsicCall>()) |
Jan Voung | 3bd9f1a | 2014-06-18 10:50:57 -0700 | [diff] [blame] | 622 | InstIntrinsicCall(Func, NumArgs, Dest, CallTarget, Info); |
| 623 | } |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 624 | static bool classof(const Inst *Instr) { |
| 625 | return Instr->getKind() == IntrinsicCall; |
Jan Voung | 3bd9f1a | 2014-06-18 10:50:57 -0700 | [diff] [blame] | 626 | } |
| 627 | |
| 628 | Intrinsics::IntrinsicInfo getIntrinsicInfo() const { return Info; } |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 629 | bool isMemoryWrite() const override { |
| 630 | return getIntrinsicInfo().IsMemoryWrite; |
| 631 | } |
Jan Voung | 3bd9f1a | 2014-06-18 10:50:57 -0700 | [diff] [blame] | 632 | |
| 633 | private: |
| 634 | InstIntrinsicCall(Cfg *Func, SizeT NumArgs, Variable *Dest, |
| 635 | Operand *CallTarget, const Intrinsics::IntrinsicInfo &Info) |
John Porto | 5e0a8a7 | 2015-11-20 13:50:36 -0800 | [diff] [blame] | 636 | : InstCall(Func, NumArgs, Dest, CallTarget, false, false, |
| 637 | Info.HasSideEffects, Inst::IntrinsicCall), |
Jan Voung | 3bd9f1a | 2014-06-18 10:50:57 -0700 | [diff] [blame] | 638 | Info(Info) {} |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 639 | |
Jan Voung | 3bd9f1a | 2014-06-18 10:50:57 -0700 | [diff] [blame] | 640 | const Intrinsics::IntrinsicInfo Info; |
| 641 | }; |
| 642 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 643 | /// Load instruction. The source address is captured in getSrc(0). |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 644 | class InstLoad : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 645 | InstLoad() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 646 | InstLoad(const InstLoad &) = delete; |
| 647 | InstLoad &operator=(const InstLoad &) = delete; |
| 648 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 649 | public: |
Karl Schimpf | 41689df | 2014-09-10 14:36:07 -0700 | [diff] [blame] | 650 | static InstLoad *create(Cfg *Func, Variable *Dest, Operand *SourceAddr, |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 651 | uint32_t Align = 1) { |
Karl Schimpf | 41689df | 2014-09-10 14:36:07 -0700 | [diff] [blame] | 652 | // TODO(kschimpf) Stop ignoring alignment specification. |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 653 | (void)Align; |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 654 | return new (Func->allocate<InstLoad>()) InstLoad(Func, Dest, SourceAddr); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 655 | } |
| 656 | Operand *getSourceAddress() const { return getSrc(0); } |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 657 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 658 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 659 | static bool classof(const Inst *Instr) { return Instr->getKind() == Load; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 660 | |
| 661 | private: |
| 662 | InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 663 | }; |
| 664 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 665 | /// Phi instruction. For incoming edge I, the node is Labels[I] and the Phi |
| 666 | /// source operand is getSrc(I). |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 667 | class InstPhi : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 668 | InstPhi() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 669 | InstPhi(const InstPhi &) = delete; |
| 670 | InstPhi &operator=(const InstPhi &) = delete; |
| 671 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 672 | public: |
| 673 | static InstPhi *create(Cfg *Func, SizeT MaxSrcs, Variable *Dest) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 674 | return new (Func->allocate<InstPhi>()) InstPhi(Func, MaxSrcs, Dest); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 675 | } |
| 676 | void addArgument(Operand *Source, CfgNode *Label); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 677 | Operand *getOperandForTarget(CfgNode *Target) const; |
David Sehr | 263ac52 | 2016-04-04 10:11:08 -0700 | [diff] [blame] | 678 | void clearOperandForTarget(CfgNode *Target); |
Jim Stichnoth | 98712a3 | 2014-10-24 10:59:02 -0700 | [diff] [blame] | 679 | CfgNode *getLabel(SizeT Index) const { return Labels[Index]; } |
Eric Holk | 16f8061 | 2016-04-04 17:07:42 -0700 | [diff] [blame] | 680 | void setLabel(SizeT Index, CfgNode *Label) { Labels[Index] = Label; } |
Jim Stichnoth | 4775255 | 2014-10-13 17:15:08 -0700 | [diff] [blame] | 681 | void livenessPhiOperand(LivenessBV &Live, CfgNode *Target, |
Jim Stichnoth | d97c7df | 2014-06-04 11:57:08 -0700 | [diff] [blame] | 682 | Liveness *Liveness); |
Jim Stichnoth | 144cdce | 2014-09-22 16:02:59 -0700 | [diff] [blame] | 683 | Inst *lower(Cfg *Func); |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 684 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 685 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 686 | static bool classof(const Inst *Instr) { return Instr->getKind() == Phi; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 687 | |
| 688 | private: |
| 689 | InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest); |
Manasij Mukherjee | 45f51a2 | 2016-06-27 16:12:37 -0700 | [diff] [blame] | 690 | void destroy(Cfg *Func) override { Inst::destroy(Func); } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 691 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 692 | /// Labels[] duplicates the InEdges[] information in the enclosing CfgNode, |
| 693 | /// but the Phi instruction is created before InEdges[] is available, so it's |
| 694 | /// more complicated to share the list. |
Manasij Mukherjee | 45f51a2 | 2016-06-27 16:12:37 -0700 | [diff] [blame] | 695 | CfgVector<CfgNode *> Labels; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 696 | }; |
| 697 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 698 | /// Ret instruction. The return value is captured in getSrc(0), but if there is |
| 699 | /// no return value (void-type function), then getSrcSize()==0 and |
| 700 | /// hasRetValue()==false. |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 701 | class InstRet : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 702 | InstRet() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 703 | InstRet(const InstRet &) = delete; |
| 704 | InstRet &operator=(const InstRet &) = delete; |
| 705 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 706 | public: |
Jim Stichnoth | ae95320 | 2014-12-20 06:17:49 -0800 | [diff] [blame] | 707 | static InstRet *create(Cfg *Func, Operand *RetValue = nullptr) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 708 | return new (Func->allocate<InstRet>()) InstRet(Func, RetValue); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 709 | } |
| 710 | bool hasRetValue() const { return getSrcSize(); } |
| 711 | Operand *getRetValue() const { |
| 712 | assert(hasRetValue()); |
| 713 | return getSrc(0); |
| 714 | } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 715 | NodeList getTerminatorEdges() const override { return NodeList(); } |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 716 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 717 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 718 | static bool classof(const Inst *Instr) { return Instr->getKind() == Ret; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 719 | |
| 720 | private: |
| 721 | InstRet(Cfg *Func, Operand *RetValue); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 722 | }; |
| 723 | |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 724 | /// Select instruction. The condition, true, and false operands are captured. |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 725 | class InstSelect : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 726 | InstSelect() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 727 | InstSelect(const InstSelect &) = delete; |
| 728 | InstSelect &operator=(const InstSelect &) = delete; |
| 729 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 730 | public: |
| 731 | static InstSelect *create(Cfg *Func, Variable *Dest, Operand *Condition, |
| 732 | Operand *SourceTrue, Operand *SourceFalse) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 733 | return new (Func->allocate<InstSelect>()) |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 734 | InstSelect(Func, Dest, Condition, SourceTrue, SourceFalse); |
| 735 | } |
| 736 | Operand *getCondition() const { return getSrc(0); } |
| 737 | Operand *getTrueOperand() const { return getSrc(1); } |
| 738 | Operand *getFalseOperand() const { return getSrc(2); } |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 739 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 740 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 741 | static bool classof(const Inst *Instr) { return Instr->getKind() == Select; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 742 | |
| 743 | private: |
| 744 | InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, Operand *Source1, |
| 745 | Operand *Source2); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 746 | }; |
| 747 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 748 | /// Store instruction. The address operand is captured, along with the data |
| 749 | /// operand to be stored into the address. |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 750 | class InstStore : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 751 | InstStore() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 752 | InstStore(const InstStore &) = delete; |
| 753 | InstStore &operator=(const InstStore &) = delete; |
| 754 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 755 | public: |
Karl Schimpf | 41689df | 2014-09-10 14:36:07 -0700 | [diff] [blame] | 756 | static InstStore *create(Cfg *Func, Operand *Data, Operand *Addr, |
Jim Stichnoth | e4f65d8 | 2015-06-17 22:16:02 -0700 | [diff] [blame] | 757 | uint32_t Align = 1) { |
Karl Schimpf | 41689df | 2014-09-10 14:36:07 -0700 | [diff] [blame] | 758 | // TODO(kschimpf) Stop ignoring alignment specification. |
Jim Stichnoth | e4f65d8 | 2015-06-17 22:16:02 -0700 | [diff] [blame] | 759 | (void)Align; |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 760 | return new (Func->allocate<InstStore>()) InstStore(Func, Data, Addr); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 761 | } |
| 762 | Operand *getAddr() const { return getSrc(1); } |
| 763 | Operand *getData() const { return getSrc(0); } |
Andrew Scull | aa6c109 | 2015-09-03 17:50:30 -0700 | [diff] [blame] | 764 | Variable *getRmwBeacon() const; |
Jim Stichnoth | e4f65d8 | 2015-06-17 22:16:02 -0700 | [diff] [blame] | 765 | void setRmwBeacon(Variable *Beacon); |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 766 | bool isMemoryWrite() const override { return true; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 767 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 768 | static bool classof(const Inst *Instr) { return Instr->getKind() == Store; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 769 | |
| 770 | private: |
| 771 | InstStore(Cfg *Func, Operand *Data, Operand *Addr); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 772 | }; |
| 773 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 774 | /// Switch instruction. The single source operand is captured as getSrc(0). |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 775 | class InstSwitch : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 776 | InstSwitch() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 777 | InstSwitch(const InstSwitch &) = delete; |
| 778 | InstSwitch &operator=(const InstSwitch &) = delete; |
| 779 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 780 | public: |
| 781 | static InstSwitch *create(Cfg *Func, SizeT NumCases, Operand *Source, |
| 782 | CfgNode *LabelDefault) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 783 | return new (Func->allocate<InstSwitch>()) |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 784 | InstSwitch(Func, NumCases, Source, LabelDefault); |
| 785 | } |
| 786 | Operand *getComparison() const { return getSrc(0); } |
| 787 | CfgNode *getLabelDefault() const { return LabelDefault; } |
| 788 | SizeT getNumCases() const { return NumCases; } |
| 789 | uint64_t getValue(SizeT I) const { |
| 790 | assert(I < NumCases); |
| 791 | return Values[I]; |
| 792 | } |
| 793 | CfgNode *getLabel(SizeT I) const { |
| 794 | assert(I < NumCases); |
| 795 | return Labels[I]; |
| 796 | } |
| 797 | void addBranch(SizeT CaseIndex, uint64_t Value, CfgNode *Label); |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 798 | NodeList getTerminatorEdges() const override; |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 799 | bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override; |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 800 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 801 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 802 | static bool classof(const Inst *Instr) { return Instr->getKind() == Switch; } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 803 | |
| 804 | private: |
| 805 | InstSwitch(Cfg *Func, SizeT NumCases, Operand *Source, CfgNode *LabelDefault); |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 806 | void destroy(Cfg *Func) override { |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 807 | Func->deallocateArrayOf<uint64_t>(Values); |
| 808 | Func->deallocateArrayOf<CfgNode *>(Labels); |
| 809 | Inst::destroy(Func); |
| 810 | } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 811 | |
| 812 | CfgNode *LabelDefault; |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 813 | SizeT NumCases; /// not including the default case |
| 814 | uint64_t *Values; /// size is NumCases |
| 815 | CfgNode **Labels; /// size is NumCases |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 816 | }; |
| 817 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 818 | /// Unreachable instruction. This is a terminator instruction with no operands. |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 819 | class InstUnreachable : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 820 | InstUnreachable() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 821 | InstUnreachable(const InstUnreachable &) = delete; |
| 822 | InstUnreachable &operator=(const InstUnreachable &) = delete; |
| 823 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 824 | public: |
| 825 | static InstUnreachable *create(Cfg *Func) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 826 | return new (Func->allocate<InstUnreachable>()) InstUnreachable(Func); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 827 | } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 828 | NodeList getTerminatorEdges() const override { return NodeList(); } |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 829 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 830 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 831 | static bool classof(const Inst *Instr) { |
| 832 | return Instr->getKind() == Unreachable; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 833 | } |
| 834 | |
| 835 | private: |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 836 | explicit InstUnreachable(Cfg *Func); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 837 | }; |
| 838 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 839 | /// BundleLock instruction. There are no operands. Contains an option |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 840 | /// indicating whether align_to_end is specified. |
Jim Stichnoth | 9f42d8c | 2015-02-20 09:20:14 -0800 | [diff] [blame] | 841 | class InstBundleLock : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 842 | InstBundleLock() = delete; |
Jim Stichnoth | 9f42d8c | 2015-02-20 09:20:14 -0800 | [diff] [blame] | 843 | InstBundleLock(const InstBundleLock &) = delete; |
| 844 | InstBundleLock &operator=(const InstBundleLock &) = delete; |
| 845 | |
| 846 | public: |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 847 | enum Option { Opt_None, Opt_AlignToEnd, Opt_PadToEnd }; |
Jim Stichnoth | 9f42d8c | 2015-02-20 09:20:14 -0800 | [diff] [blame] | 848 | static InstBundleLock *create(Cfg *Func, Option BundleOption) { |
| 849 | return new (Func->allocate<InstBundleLock>()) |
| 850 | InstBundleLock(Func, BundleOption); |
| 851 | } |
| 852 | void emit(const Cfg *Func) const override; |
| 853 | void emitIAS(const Cfg * /* Func */) const override {} |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 854 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | 9f42d8c | 2015-02-20 09:20:14 -0800 | [diff] [blame] | 855 | void dump(const Cfg *Func) const override; |
| 856 | Option getOption() const { return BundleOption; } |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 857 | static bool classof(const Inst *Instr) { |
| 858 | return Instr->getKind() == BundleLock; |
Jim Stichnoth | 9f42d8c | 2015-02-20 09:20:14 -0800 | [diff] [blame] | 859 | } |
| 860 | |
| 861 | private: |
| 862 | Option BundleOption; |
| 863 | InstBundleLock(Cfg *Func, Option BundleOption); |
Jim Stichnoth | 9f42d8c | 2015-02-20 09:20:14 -0800 | [diff] [blame] | 864 | }; |
| 865 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 866 | /// BundleUnlock instruction. There are no operands. |
Jim Stichnoth | 9f42d8c | 2015-02-20 09:20:14 -0800 | [diff] [blame] | 867 | class InstBundleUnlock : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 868 | InstBundleUnlock() = delete; |
Jim Stichnoth | 9f42d8c | 2015-02-20 09:20:14 -0800 | [diff] [blame] | 869 | InstBundleUnlock(const InstBundleUnlock &) = delete; |
| 870 | InstBundleUnlock &operator=(const InstBundleUnlock &) = delete; |
| 871 | |
| 872 | public: |
| 873 | static InstBundleUnlock *create(Cfg *Func) { |
| 874 | return new (Func->allocate<InstBundleUnlock>()) InstBundleUnlock(Func); |
| 875 | } |
| 876 | void emit(const Cfg *Func) const override; |
| 877 | void emitIAS(const Cfg * /* Func */) const override {} |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 878 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | 9f42d8c | 2015-02-20 09:20:14 -0800 | [diff] [blame] | 879 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 880 | static bool classof(const Inst *Instr) { |
| 881 | return Instr->getKind() == BundleUnlock; |
Jim Stichnoth | 9f42d8c | 2015-02-20 09:20:14 -0800 | [diff] [blame] | 882 | } |
| 883 | |
| 884 | private: |
| 885 | explicit InstBundleUnlock(Cfg *Func); |
Jim Stichnoth | 9f42d8c | 2015-02-20 09:20:14 -0800 | [diff] [blame] | 886 | }; |
| 887 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 888 | /// FakeDef instruction. This creates a fake definition of a variable, which is |
| 889 | /// how we represent the case when an instruction produces multiple results. |
| 890 | /// This doesn't happen with high-level ICE instructions, but might with lowered |
| 891 | /// instructions. For example, this would be a way to represent condition flags |
| 892 | /// being modified by an instruction. |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 893 | /// |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 894 | /// It's generally useful to set the optional source operand to be the dest |
| 895 | /// variable of the instruction that actually produces the FakeDef dest. |
| 896 | /// Otherwise, the original instruction could be dead-code eliminated if its |
| 897 | /// dest operand is unused, and therefore the FakeDef dest wouldn't be properly |
| 898 | /// initialized. |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 899 | class InstFakeDef : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 900 | InstFakeDef() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 901 | InstFakeDef(const InstFakeDef &) = delete; |
| 902 | InstFakeDef &operator=(const InstFakeDef &) = delete; |
| 903 | |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 904 | public: |
Jim Stichnoth | ae95320 | 2014-12-20 06:17:49 -0800 | [diff] [blame] | 905 | static InstFakeDef *create(Cfg *Func, Variable *Dest, |
| 906 | Variable *Src = nullptr) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 907 | return new (Func->allocate<InstFakeDef>()) InstFakeDef(Func, Dest, Src); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 908 | } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 909 | void emit(const Cfg *Func) const override; |
Jan Voung | 198b294 | 2014-10-16 09:40:02 -0700 | [diff] [blame] | 910 | void emitIAS(const Cfg * /* Func */) const override {} |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 911 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 912 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 913 | static bool classof(const Inst *Instr) { return Instr->getKind() == FakeDef; } |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 914 | |
| 915 | private: |
| 916 | InstFakeDef(Cfg *Func, Variable *Dest, Variable *Src); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 917 | }; |
| 918 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 919 | /// FakeUse instruction. This creates a fake use of a variable, to keep the |
| 920 | /// instruction that produces that variable from being dead-code eliminated. |
| 921 | /// This is useful in a variety of lowering situations. The FakeUse instruction |
Jim Stichnoth | 8ff4b28 | 2016-01-04 15:39:06 -0800 | [diff] [blame] | 922 | /// has no dest, so it can itself never be dead-code eliminated. A weight can |
| 923 | /// be provided to provide extra bias to the register allocator - for simplicity |
| 924 | /// of implementation, weight=N is handled by holding N copies of the variable |
| 925 | /// as source operands. |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 926 | class InstFakeUse : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 927 | InstFakeUse() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 928 | InstFakeUse(const InstFakeUse &) = delete; |
| 929 | InstFakeUse &operator=(const InstFakeUse &) = delete; |
| 930 | |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 931 | public: |
Jim Stichnoth | 8ff4b28 | 2016-01-04 15:39:06 -0800 | [diff] [blame] | 932 | static InstFakeUse *create(Cfg *Func, Variable *Src, uint32_t Weight = 1) { |
| 933 | return new (Func->allocate<InstFakeUse>()) InstFakeUse(Func, Src, Weight); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 934 | } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 935 | void emit(const Cfg *Func) const override; |
Jan Voung | 198b294 | 2014-10-16 09:40:02 -0700 | [diff] [blame] | 936 | void emitIAS(const Cfg * /* Func */) const override {} |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 937 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 938 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 939 | static bool classof(const Inst *Instr) { return Instr->getKind() == FakeUse; } |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 940 | |
| 941 | private: |
Jim Stichnoth | 8ff4b28 | 2016-01-04 15:39:06 -0800 | [diff] [blame] | 942 | InstFakeUse(Cfg *Func, Variable *Src, uint32_t Weight); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 943 | }; |
| 944 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 945 | /// FakeKill instruction. This "kills" a set of variables by modeling a trivial |
| 946 | /// live range at this instruction for each (implicit) variable. The primary use |
| 947 | /// is to indicate that scratch registers are killed after a call, so that the |
| 948 | /// register allocator won't assign a scratch register to a variable whose live |
| 949 | /// range spans a call. |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 950 | /// |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 951 | /// The FakeKill instruction also holds a pointer to the instruction that kills |
| 952 | /// the set of variables, so that if that linked instruction gets dead-code |
| 953 | /// eliminated, the FakeKill instruction will as well. |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 954 | class InstFakeKill : public InstHighLevel { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 955 | InstFakeKill() = delete; |
Jim Stichnoth | 7b451a9 | 2014-10-15 14:39:23 -0700 | [diff] [blame] | 956 | InstFakeKill(const InstFakeKill &) = delete; |
| 957 | InstFakeKill &operator=(const InstFakeKill &) = delete; |
| 958 | |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 959 | public: |
Jim Stichnoth | 87ff3a1 | 2014-11-14 10:27:29 -0800 | [diff] [blame] | 960 | static InstFakeKill *create(Cfg *Func, const Inst *Linked) { |
Jim Stichnoth | 31c9559 | 2014-12-19 12:51:35 -0800 | [diff] [blame] | 961 | return new (Func->allocate<InstFakeKill>()) InstFakeKill(Func, Linked); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 962 | } |
| 963 | const Inst *getLinked() const { return Linked; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 964 | void emit(const Cfg *Func) const override; |
Jan Voung | 198b294 | 2014-10-16 09:40:02 -0700 | [diff] [blame] | 965 | void emitIAS(const Cfg * /* Func */) const override {} |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 966 | bool isMemoryWrite() const override { return false; } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 967 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 968 | static bool classof(const Inst *Instr) { |
| 969 | return Instr->getKind() == FakeKill; |
| 970 | } |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 971 | |
| 972 | private: |
Jim Stichnoth | 87ff3a1 | 2014-11-14 10:27:29 -0800 | [diff] [blame] | 973 | InstFakeKill(Cfg *Func, const Inst *Linked); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 974 | |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 975 | /// This instruction is ignored if Linked->isDeleted() is true. |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 976 | const Inst *Linked; |
| 977 | }; |
| 978 | |
John Porto | a47c11c | 2016-04-21 05:53:42 -0700 | [diff] [blame] | 979 | /// ShuffleVector instruction. This represents a shuffle operation on vector |
| 980 | /// types. This instruction is not part of the PNaCl bitcode: it is generated |
| 981 | /// by Subzero when it matches the pattern used by pnacl-clang when compiling |
| 982 | /// to bitcode. |
| 983 | class InstShuffleVector : public InstHighLevel { |
| 984 | InstShuffleVector() = delete; |
| 985 | InstShuffleVector(const InstShuffleVector &) = delete; |
| 986 | InstShuffleVector &operator=(const InstShuffleVector &) = delete; |
| 987 | |
| 988 | public: |
Nicolas Capens | 579b1b3 | 2016-12-09 14:56:03 -0500 | [diff] [blame] | 989 | static InstShuffleVector *create(Cfg *Func, Variable *Dest, Operand *Src0, |
| 990 | Operand *Src1) { |
John Porto | a47c11c | 2016-04-21 05:53:42 -0700 | [diff] [blame] | 991 | return new (Func->allocate<InstShuffleVector>()) |
| 992 | InstShuffleVector(Func, Dest, Src0, Src1); |
| 993 | } |
| 994 | |
| 995 | SizeT getNumIndexes() const { return NumIndexes; } |
| 996 | |
| 997 | void addIndex(ConstantInteger32 *Index) { |
| 998 | assert(CurrentIndex < NumIndexes); |
| 999 | Indexes[CurrentIndex++] = Index; |
| 1000 | } |
| 1001 | |
| 1002 | ConstantInteger32 *getIndex(SizeT Pos) const { |
| 1003 | assert(Pos < NumIndexes); |
| 1004 | return Indexes[Pos]; |
| 1005 | } |
| 1006 | |
Nicolas Capens | f6951fa | 2017-10-02 10:44:03 -0400 | [diff] [blame] | 1007 | int32_t getIndexValue(SizeT Pos) const { return getIndex(Pos)->getValue(); } |
| 1008 | |
| 1009 | bool indexesAre(int32_t i0, int32_t i1, int32_t i2, int32_t i3) const { |
| 1010 | static constexpr SizeT ExpectedNumElements = 4; |
| 1011 | assert(ExpectedNumElements == getNumIndexes()); |
| 1012 | (void)ExpectedNumElements; |
| 1013 | |
| 1014 | return getIndexValue(0) == i0 && getIndexValue(1) == i1 && |
| 1015 | getIndexValue(2) == i2 && getIndexValue(3) == i3; |
| 1016 | } |
| 1017 | |
| 1018 | bool indexesAre(int32_t i0, int32_t i1, int32_t i2, int32_t i3, int32_t i4, |
| 1019 | int32_t i5, int32_t i6, int32_t i7) const { |
Nicolas Capens | 1448d95 | 2016-10-14 16:37:09 -0400 | [diff] [blame] | 1020 | static constexpr SizeT ExpectedNumElements = 8; |
| 1021 | assert(ExpectedNumElements == getNumIndexes()); |
| 1022 | (void)ExpectedNumElements; |
| 1023 | |
Nicolas Capens | f6951fa | 2017-10-02 10:44:03 -0400 | [diff] [blame] | 1024 | return getIndexValue(0) == i0 && getIndexValue(1) == i1 && |
| 1025 | getIndexValue(2) == i2 && getIndexValue(3) == i3 && |
| 1026 | getIndexValue(4) == i4 && getIndexValue(5) == i5 && |
| 1027 | getIndexValue(6) == i6 && getIndexValue(7) == i7; |
Nicolas Capens | 1448d95 | 2016-10-14 16:37:09 -0400 | [diff] [blame] | 1028 | } |
| 1029 | |
Nicolas Capens | f6951fa | 2017-10-02 10:44:03 -0400 | [diff] [blame] | 1030 | bool indexesAre(int32_t i0, int32_t i1, int32_t i2, int32_t i3, int32_t i4, |
| 1031 | int32_t i5, int32_t i6, int32_t i7, int32_t i8, int32_t i9, |
| 1032 | int32_t i10, int32_t i11, int32_t i12, int32_t i13, |
| 1033 | int32_t i14, int32_t i15) const { |
Nicolas Capens | 1448d95 | 2016-10-14 16:37:09 -0400 | [diff] [blame] | 1034 | static constexpr SizeT ExpectedNumElements = 16; |
| 1035 | assert(ExpectedNumElements == getNumIndexes()); |
| 1036 | (void)ExpectedNumElements; |
| 1037 | |
Nicolas Capens | f6951fa | 2017-10-02 10:44:03 -0400 | [diff] [blame] | 1038 | return getIndexValue(0) == i0 && getIndexValue(1) == i1 && |
| 1039 | getIndexValue(2) == i2 && getIndexValue(3) == i3 && |
| 1040 | getIndexValue(4) == i4 && getIndexValue(5) == i5 && |
| 1041 | getIndexValue(6) == i6 && getIndexValue(7) == i7 && |
| 1042 | getIndexValue(8) == i8 && getIndexValue(9) == i9 && |
| 1043 | getIndexValue(10) == i10 && getIndexValue(11) == i11 && |
| 1044 | getIndexValue(12) == i12 && getIndexValue(13) == i13 && |
| 1045 | getIndexValue(14) == i14 && getIndexValue(15) == i15; |
Nicolas Capens | 1448d95 | 2016-10-14 16:37:09 -0400 | [diff] [blame] | 1046 | } |
| 1047 | |
Jim Stichnoth | cd261e9 | 2016-04-21 17:57:56 -0700 | [diff] [blame] | 1048 | bool isMemoryWrite() const override { return false; } |
John Porto | a47c11c | 2016-04-21 05:53:42 -0700 | [diff] [blame] | 1049 | void dump(const Cfg *Func) const override; |
| 1050 | static bool classof(const Inst *Instr) { |
| 1051 | return Instr->getKind() == ShuffleVector; |
| 1052 | } |
| 1053 | |
| 1054 | private: |
Nicolas Capens | 579b1b3 | 2016-12-09 14:56:03 -0500 | [diff] [blame] | 1055 | InstShuffleVector(Cfg *Func, Variable *Dest, Operand *Src0, Operand *Src1); |
John Porto | a47c11c | 2016-04-21 05:53:42 -0700 | [diff] [blame] | 1056 | |
| 1057 | void destroy(Cfg *Func) override { |
| 1058 | Func->deallocateArrayOf<ConstantInteger32 *>(Indexes); |
| 1059 | Inst::destroy(Func); |
| 1060 | } |
| 1061 | |
| 1062 | ConstantInteger32 **Indexes; |
| 1063 | SizeT CurrentIndex = 0; |
| 1064 | const SizeT NumIndexes; |
| 1065 | }; |
| 1066 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 1067 | /// JumpTable instruction. This represents a jump table that will be stored in |
| 1068 | /// the .rodata section. This is used to track and repoint the target CfgNodes |
| 1069 | /// which may change, for example due to splitting for phi lowering. |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 1070 | class InstJumpTable : public InstHighLevel { |
| 1071 | InstJumpTable() = delete; |
| 1072 | InstJumpTable(const InstJumpTable &) = delete; |
| 1073 | InstJumpTable &operator=(const InstJumpTable &) = delete; |
| 1074 | |
| 1075 | public: |
| 1076 | static InstJumpTable *create(Cfg *Func, SizeT NumTargets, CfgNode *Default) { |
| 1077 | return new (Func->allocate<InstJumpTable>()) |
| 1078 | InstJumpTable(Func, NumTargets, Default); |
| 1079 | } |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 1080 | void addTarget(SizeT TargetIndex, CfgNode *Target) { |
| 1081 | assert(TargetIndex < NumTargets); |
| 1082 | Targets[TargetIndex] = Target; |
| 1083 | } |
| 1084 | bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override; |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 1085 | SizeT getId() const { return Id; } |
| 1086 | SizeT getNumTargets() const { return NumTargets; } |
| 1087 | CfgNode *getTarget(SizeT I) const { |
| 1088 | assert(I < NumTargets); |
| 1089 | return Targets[I]; |
| 1090 | } |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 1091 | bool isMemoryWrite() const override { return false; } |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 1092 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 1093 | static bool classof(const Inst *Instr) { |
| 1094 | return Instr->getKind() == JumpTable; |
| 1095 | } |
John Porto | 0307721 | 2016-04-05 06:30:21 -0700 | [diff] [blame] | 1096 | // Creates a JumpTableData struct (used for ELF emission) that represents this |
| 1097 | // InstJumpTable. |
| 1098 | JumpTableData toJumpTableData(Assembler *Asm) const; |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 1099 | |
John Porto | 0307721 | 2016-04-05 06:30:21 -0700 | [diff] [blame] | 1100 | // InstJumpTable is just a placeholder for the switch targets, and it does not |
| 1101 | // need to emit any code, so we redefine emit and emitIAS to do nothing. |
| 1102 | void emit(const Cfg *) const override {} |
| 1103 | void emitIAS(const Cfg * /* Func */) const override {} |
| 1104 | |
| 1105 | const std::string getName() const { |
| 1106 | assert(Name.hasStdString()); |
| 1107 | return Name.toString(); |
| 1108 | } |
| 1109 | |
| 1110 | std::string getSectionName() const { |
| 1111 | return JumpTableData::createSectionName(FuncName); |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 1112 | } |
| 1113 | |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 1114 | private: |
| 1115 | InstJumpTable(Cfg *Func, SizeT NumTargets, CfgNode *Default); |
| 1116 | void destroy(Cfg *Func) override { |
| 1117 | Func->deallocateArrayOf<CfgNode *>(Targets); |
| 1118 | Inst::destroy(Func); |
| 1119 | } |
| 1120 | |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 1121 | const SizeT Id; |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 1122 | const SizeT NumTargets; |
| 1123 | CfgNode **Targets; |
John Porto | 0307721 | 2016-04-05 06:30:21 -0700 | [diff] [blame] | 1124 | GlobalString Name; // This JumpTable's name in the output. |
| 1125 | GlobalString FuncName; |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 1126 | }; |
| 1127 | |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame] | 1128 | /// This instruction inserts an unconditional breakpoint. |
| 1129 | /// |
| 1130 | /// On x86, this assembles into an INT 3 instruction. |
| 1131 | /// |
| 1132 | /// This instruction is primarily meant for debugging the code generator. |
| 1133 | class InstBreakpoint : public InstHighLevel { |
| 1134 | public: |
| 1135 | InstBreakpoint() = delete; |
| 1136 | InstBreakpoint(const InstBreakpoint &) = delete; |
| 1137 | InstBreakpoint &operator=(const InstBreakpoint &) = delete; |
| 1138 | |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 1139 | explicit InstBreakpoint(Cfg *Func); |
| 1140 | bool isMemoryWrite() const override { return false; } |
Eric Holk | 67c7c41 | 2016-04-15 13:05:37 -0700 | [diff] [blame] | 1141 | |
| 1142 | public: |
| 1143 | static InstBreakpoint *create(Cfg *Func) { |
| 1144 | return new (Func->allocate<InstBreakpoint>()) InstBreakpoint(Func); |
| 1145 | } |
| 1146 | |
| 1147 | static bool classof(const Inst *Instr) { |
| 1148 | return Instr->getKind() == Breakpoint; |
| 1149 | } |
| 1150 | }; |
| 1151 | |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 1152 | /// The Target instruction is the base class for all target-specific |
| 1153 | /// instructions. |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 1154 | class InstTarget : public Inst { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 1155 | InstTarget() = delete; |
Jim Stichnoth | 0795ba0 | 2014-10-01 14:23:01 -0700 | [diff] [blame] | 1156 | InstTarget(const InstTarget &) = delete; |
| 1157 | InstTarget &operator=(const InstTarget &) = delete; |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 1158 | |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 1159 | public: |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 1160 | uint32_t getEmitInstCount() const override { return 1; } |
Jim Stichnoth | f1f773d | 2016-04-21 16:54:33 -0700 | [diff] [blame] | 1161 | bool isMemoryWrite() const override { |
| 1162 | return true; // conservative answer |
| 1163 | } |
Jim Stichnoth | b56c8f4 | 2014-09-26 09:28:46 -0700 | [diff] [blame] | 1164 | void dump(const Cfg *Func) const override; |
Jim Stichnoth | 8cfeb69 | 2016-02-05 09:50:02 -0800 | [diff] [blame] | 1165 | static bool classof(const Inst *Instr) { return Instr->getKind() >= Target; } |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 1166 | |
| 1167 | protected: |
| 1168 | InstTarget(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) |
| 1169 | : Inst(Func, Kind, MaxSrcs, Dest) { |
| 1170 | assert(Kind >= Target); |
Andrew Scull | 6ef7949 | 2015-09-09 15:50:42 -0700 | [diff] [blame] | 1171 | assert(Kind <= Target_Max); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 1172 | } |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 1173 | }; |
| 1174 | |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 1175 | bool checkForRedundantAssign(const Variable *Dest, const Operand *Source); |
| 1176 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 1177 | } // end of namespace Ice |
| 1178 | |
Jim Stichnoth | 8b21cc5 | 2016-08-29 10:15:18 -0700 | [diff] [blame] | 1179 | #ifdef PNACL_LLVM |
Jim Stichnoth | dddaf9c | 2014-12-04 14:09:21 -0800 | [diff] [blame] | 1180 | namespace llvm { |
| 1181 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 1182 | /// Override the default ilist traits so that Inst's private ctor and deleted |
| 1183 | /// dtor aren't invoked. |
Jim Stichnoth | 607e9f0 | 2014-11-06 13:32:05 -0800 | [diff] [blame] | 1184 | template <> |
Jim Stichnoth | dddaf9c | 2014-12-04 14:09:21 -0800 | [diff] [blame] | 1185 | struct ilist_traits<Ice::Inst> : public ilist_default_traits<Ice::Inst> { |
Jim Stichnoth | 607e9f0 | 2014-11-06 13:32:05 -0800 | [diff] [blame] | 1186 | Ice::Inst *createSentinel() const { |
| 1187 | return static_cast<Ice::Inst *>(&Sentinel); |
| 1188 | } |
| 1189 | static void destroySentinel(Ice::Inst *) {} |
| 1190 | Ice::Inst *provideInitialHead() const { return createSentinel(); } |
| 1191 | Ice::Inst *ensureHead(Ice::Inst *) const { return createSentinel(); } |
| 1192 | static void noteHead(Ice::Inst *, Ice::Inst *) {} |
| 1193 | void deleteNode(Ice::Inst *) {} |
| 1194 | |
| 1195 | private: |
| 1196 | mutable ilist_half_node<Ice::Inst> Sentinel; |
| 1197 | }; |
| 1198 | |
Jim Stichnoth | dddaf9c | 2014-12-04 14:09:21 -0800 | [diff] [blame] | 1199 | } // end of namespace llvm |
Jim Stichnoth | 8b21cc5 | 2016-08-29 10:15:18 -0700 | [diff] [blame] | 1200 | #endif // PNACL_LLVM |
Jim Stichnoth | dddaf9c | 2014-12-04 14:09:21 -0800 | [diff] [blame] | 1201 | |
Jim Stichnoth | f5fdd23 | 2016-05-09 12:24:36 -0700 | [diff] [blame] | 1202 | namespace Ice { |
| 1203 | |
| 1204 | inline InstList::iterator instToIterator(Inst *Instr) { |
| 1205 | #ifdef PNACL_LLVM |
| 1206 | return Instr; |
Jim Stichnoth | a5b16ab | 2016-05-10 11:20:41 -0700 | [diff] [blame] | 1207 | #else // !PNACL_LLVM |
Jim Stichnoth | f5fdd23 | 2016-05-09 12:24:36 -0700 | [diff] [blame] | 1208 | return Instr->getIterator(); |
| 1209 | #endif // !PNACL_LLVM |
| 1210 | } |
| 1211 | |
Jim Stichnoth | a5b16ab | 2016-05-10 11:20:41 -0700 | [diff] [blame] | 1212 | inline Inst *iteratorToInst(InstList::iterator Iter) { return &*Iter; } |
Jim Stichnoth | f5fdd23 | 2016-05-09 12:24:36 -0700 | [diff] [blame] | 1213 | |
| 1214 | inline const Inst *iteratorToInst(InstList::const_iterator Iter) { |
| 1215 | return &*Iter; |
| 1216 | } |
| 1217 | |
Jim Stichnoth | 7c9728f | 2016-08-31 13:42:00 -0700 | [diff] [blame] | 1218 | inline InstList::iterator |
| 1219 | reverseToForwardIterator(InstList::reverse_iterator RI) { |
| 1220 | #ifdef PNACL_LLVM |
| 1221 | return RI.base(); |
| 1222 | #else // !PNACL_LLVM |
| 1223 | return ++RI.getReverse(); |
| 1224 | #endif // !PNACL_LLVM |
| 1225 | } |
| 1226 | |
Jim Stichnoth | f5fdd23 | 2016-05-09 12:24:36 -0700 | [diff] [blame] | 1227 | } // end of namespace Ice |
| 1228 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 1229 | #endif // SUBZERO_SRC_ICEINST_H |