1303231Sdim//===- llvm/CodeGen/MachineInstrBundleIterator.h ----------------*- C++ -*-===// 2303231Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6303231Sdim// 7303231Sdim//===----------------------------------------------------------------------===// 8303231Sdim// 9303231Sdim// Defines an iterator class that bundles MachineInstr. 10303231Sdim// 11303231Sdim//===----------------------------------------------------------------------===// 12303231Sdim 13303231Sdim#ifndef LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H 14303231Sdim#define LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H 15303231Sdim 16303231Sdim#include "llvm/ADT/ilist.h" 17321369Sdim#include "llvm/ADT/simple_ilist.h" 18321369Sdim#include <cassert> 19303231Sdim#include <iterator> 20321369Sdim#include <type_traits> 21303231Sdim 22303231Sdimnamespace llvm { 23303231Sdim 24314564Sdimtemplate <class T, bool IsReverse> struct MachineInstrBundleIteratorTraits; 25314564Sdimtemplate <class T> struct MachineInstrBundleIteratorTraits<T, false> { 26321369Sdim using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>; 27321369Sdim using instr_iterator = typename list_type::iterator; 28321369Sdim using nonconst_instr_iterator = typename list_type::iterator; 29321369Sdim using const_instr_iterator = typename list_type::const_iterator; 30314564Sdim}; 31314564Sdimtemplate <class T> struct MachineInstrBundleIteratorTraits<T, true> { 32321369Sdim using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>; 33321369Sdim using instr_iterator = typename list_type::reverse_iterator; 34321369Sdim using nonconst_instr_iterator = typename list_type::reverse_iterator; 35321369Sdim using const_instr_iterator = typename list_type::const_reverse_iterator; 36314564Sdim}; 37314564Sdimtemplate <class T> struct MachineInstrBundleIteratorTraits<const T, false> { 38321369Sdim using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>; 39321369Sdim using instr_iterator = typename list_type::const_iterator; 40321369Sdim using nonconst_instr_iterator = typename list_type::iterator; 41321369Sdim using const_instr_iterator = typename list_type::const_iterator; 42314564Sdim}; 43314564Sdimtemplate <class T> struct MachineInstrBundleIteratorTraits<const T, true> { 44321369Sdim using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>; 45321369Sdim using instr_iterator = typename list_type::const_reverse_iterator; 46321369Sdim using nonconst_instr_iterator = typename list_type::reverse_iterator; 47321369Sdim using const_instr_iterator = typename list_type::const_reverse_iterator; 48314564Sdim}; 49314564Sdim 50314564Sdimtemplate <bool IsReverse> struct MachineInstrBundleIteratorHelper; 51314564Sdimtemplate <> struct MachineInstrBundleIteratorHelper<false> { 52314564Sdim /// Get the beginning of the current bundle. 53314564Sdim template <class Iterator> static Iterator getBundleBegin(Iterator I) { 54314564Sdim if (!I.isEnd()) 55314564Sdim while (I->isBundledWithPred()) 56314564Sdim --I; 57314564Sdim return I; 58314564Sdim } 59314564Sdim 60314564Sdim /// Get the final node of the current bundle. 61314564Sdim template <class Iterator> static Iterator getBundleFinal(Iterator I) { 62314564Sdim if (!I.isEnd()) 63314564Sdim while (I->isBundledWithSucc()) 64314564Sdim ++I; 65314564Sdim return I; 66314564Sdim } 67314564Sdim 68314564Sdim /// Increment forward ilist iterator. 69314564Sdim template <class Iterator> static void increment(Iterator &I) { 70314564Sdim I = std::next(getBundleFinal(I)); 71314564Sdim } 72314564Sdim 73314564Sdim /// Decrement forward ilist iterator. 74314564Sdim template <class Iterator> static void decrement(Iterator &I) { 75314564Sdim I = getBundleBegin(std::prev(I)); 76314564Sdim } 77314564Sdim}; 78314564Sdim 79314564Sdimtemplate <> struct MachineInstrBundleIteratorHelper<true> { 80314564Sdim /// Get the beginning of the current bundle. 81314564Sdim template <class Iterator> static Iterator getBundleBegin(Iterator I) { 82314564Sdim return MachineInstrBundleIteratorHelper<false>::getBundleBegin( 83314564Sdim I.getReverse()) 84314564Sdim .getReverse(); 85314564Sdim } 86314564Sdim 87314564Sdim /// Get the final node of the current bundle. 88314564Sdim template <class Iterator> static Iterator getBundleFinal(Iterator I) { 89314564Sdim return MachineInstrBundleIteratorHelper<false>::getBundleFinal( 90314564Sdim I.getReverse()) 91314564Sdim .getReverse(); 92314564Sdim } 93314564Sdim 94314564Sdim /// Increment reverse ilist iterator. 95314564Sdim template <class Iterator> static void increment(Iterator &I) { 96314564Sdim I = getBundleBegin(std::next(I)); 97314564Sdim } 98314564Sdim 99314564Sdim /// Decrement reverse ilist iterator. 100314564Sdim template <class Iterator> static void decrement(Iterator &I) { 101314564Sdim I = std::prev(getBundleFinal(I)); 102314564Sdim } 103314564Sdim}; 104314564Sdim 105303231Sdim/// MachineBasicBlock iterator that automatically skips over MIs that are 106303231Sdim/// inside bundles (i.e. walk top level MIs only). 107314564Sdimtemplate <typename Ty, bool IsReverse = false> 108314564Sdimclass MachineInstrBundleIterator : MachineInstrBundleIteratorHelper<IsReverse> { 109321369Sdim using Traits = MachineInstrBundleIteratorTraits<Ty, IsReverse>; 110321369Sdim using instr_iterator = typename Traits::instr_iterator; 111321369Sdim 112303231Sdim instr_iterator MII; 113303231Sdim 114303231Sdimpublic: 115321369Sdim using value_type = typename instr_iterator::value_type; 116321369Sdim using difference_type = typename instr_iterator::difference_type; 117321369Sdim using pointer = typename instr_iterator::pointer; 118321369Sdim using reference = typename instr_iterator::reference; 119321369Sdim using const_pointer = typename instr_iterator::const_pointer; 120321369Sdim using const_reference = typename instr_iterator::const_reference; 121321369Sdim using iterator_category = std::bidirectional_iterator_tag; 122303231Sdim 123314564Sdimprivate: 124321369Sdim using nonconst_instr_iterator = typename Traits::nonconst_instr_iterator; 125321369Sdim using const_instr_iterator = typename Traits::const_instr_iterator; 126321369Sdim using nonconst_iterator = 127321369Sdim MachineInstrBundleIterator<typename nonconst_instr_iterator::value_type, 128321369Sdim IsReverse>; 129321369Sdim using reverse_iterator = MachineInstrBundleIterator<Ty, !IsReverse>; 130314564Sdim 131314564Sdimpublic: 132314564Sdim MachineInstrBundleIterator(instr_iterator MI) : MII(MI) { 133314564Sdim assert((!MI.getNodePtr() || MI.isEnd() || !MI->isBundledWithPred()) && 134314564Sdim "It's not legal to initialize MachineInstrBundleIterator with a " 135314564Sdim "bundled MI"); 136314564Sdim } 137314564Sdim 138314564Sdim MachineInstrBundleIterator(reference MI) : MII(MI) { 139303231Sdim assert(!MI.isBundledWithPred() && "It's not legal to initialize " 140303231Sdim "MachineInstrBundleIterator with a " 141303231Sdim "bundled MI"); 142303231Sdim } 143321369Sdim 144314564Sdim MachineInstrBundleIterator(pointer MI) : MII(MI) { 145303231Sdim // FIXME: This conversion should be explicit. 146303231Sdim assert((!MI || !MI->isBundledWithPred()) && "It's not legal to initialize " 147303231Sdim "MachineInstrBundleIterator " 148303231Sdim "with a bundled MI"); 149303231Sdim } 150321369Sdim 151303231Sdim // Template allows conversion from const to nonconst. 152303231Sdim template <class OtherTy> 153314564Sdim MachineInstrBundleIterator( 154314564Sdim const MachineInstrBundleIterator<OtherTy, IsReverse> &I, 155314564Sdim typename std::enable_if<std::is_convertible<OtherTy *, Ty *>::value, 156314564Sdim void *>::type = nullptr) 157303231Sdim : MII(I.getInstrIterator()) {} 158321369Sdim 159303231Sdim MachineInstrBundleIterator() : MII(nullptr) {} 160303231Sdim 161314564Sdim /// Explicit conversion between forward/reverse iterators. 162314564Sdim /// 163314564Sdim /// Translate between forward and reverse iterators without changing range 164314564Sdim /// boundaries. The resulting iterator will dereference (and have a handle) 165314564Sdim /// to the previous node, which is somewhat unexpected; but converting the 166314564Sdim /// two endpoints in a range will give the same range in reverse. 167314564Sdim /// 168314564Sdim /// This matches std::reverse_iterator conversions. 169314564Sdim explicit MachineInstrBundleIterator( 170314564Sdim const MachineInstrBundleIterator<Ty, !IsReverse> &I) 171314564Sdim : MachineInstrBundleIterator(++I.getReverse()) {} 172303231Sdim 173314564Sdim /// Get the bundle iterator for the given instruction's bundle. 174314564Sdim static MachineInstrBundleIterator getAtBundleBegin(instr_iterator MI) { 175314564Sdim return MachineInstrBundleIteratorHelper<IsReverse>::getBundleBegin(MI); 176314564Sdim } 177303231Sdim 178314564Sdim reference operator*() const { return *MII; } 179314564Sdim pointer operator->() const { return &operator*(); } 180314564Sdim 181314564Sdim /// Check for null. 182314564Sdim bool isValid() const { return MII.getNodePtr(); } 183314564Sdim 184314564Sdim friend bool operator==(const MachineInstrBundleIterator &L, 185314564Sdim const MachineInstrBundleIterator &R) { 186314564Sdim return L.MII == R.MII; 187303231Sdim } 188314564Sdim friend bool operator==(const MachineInstrBundleIterator &L, 189314564Sdim const const_instr_iterator &R) { 190314564Sdim return L.MII == R; // Avoid assertion about validity of R. 191303231Sdim } 192314564Sdim friend bool operator==(const const_instr_iterator &L, 193314564Sdim const MachineInstrBundleIterator &R) { 194314564Sdim return L == R.MII; // Avoid assertion about validity of L. 195314564Sdim } 196314564Sdim friend bool operator==(const MachineInstrBundleIterator &L, 197314564Sdim const nonconst_instr_iterator &R) { 198314564Sdim return L.MII == R; // Avoid assertion about validity of R. 199314564Sdim } 200314564Sdim friend bool operator==(const nonconst_instr_iterator &L, 201314564Sdim const MachineInstrBundleIterator &R) { 202314564Sdim return L == R.MII; // Avoid assertion about validity of L. 203314564Sdim } 204314564Sdim friend bool operator==(const MachineInstrBundleIterator &L, const_pointer R) { 205314564Sdim return L == const_instr_iterator(R); // Avoid assertion about validity of R. 206314564Sdim } 207314564Sdim friend bool operator==(const_pointer L, const MachineInstrBundleIterator &R) { 208314564Sdim return const_instr_iterator(L) == R; // Avoid assertion about validity of L. 209314564Sdim } 210314564Sdim friend bool operator==(const MachineInstrBundleIterator &L, 211314564Sdim const_reference R) { 212314564Sdim return L == &R; // Avoid assertion about validity of R. 213314564Sdim } 214314564Sdim friend bool operator==(const_reference L, 215314564Sdim const MachineInstrBundleIterator &R) { 216314564Sdim return &L == R; // Avoid assertion about validity of L. 217314564Sdim } 218303231Sdim 219314564Sdim friend bool operator!=(const MachineInstrBundleIterator &L, 220314564Sdim const MachineInstrBundleIterator &R) { 221314564Sdim return !(L == R); 222314564Sdim } 223314564Sdim friend bool operator!=(const MachineInstrBundleIterator &L, 224314564Sdim const const_instr_iterator &R) { 225314564Sdim return !(L == R); 226314564Sdim } 227314564Sdim friend bool operator!=(const const_instr_iterator &L, 228314564Sdim const MachineInstrBundleIterator &R) { 229314564Sdim return !(L == R); 230314564Sdim } 231314564Sdim friend bool operator!=(const MachineInstrBundleIterator &L, 232314564Sdim const nonconst_instr_iterator &R) { 233314564Sdim return !(L == R); 234314564Sdim } 235314564Sdim friend bool operator!=(const nonconst_instr_iterator &L, 236314564Sdim const MachineInstrBundleIterator &R) { 237314564Sdim return !(L == R); 238314564Sdim } 239314564Sdim friend bool operator!=(const MachineInstrBundleIterator &L, const_pointer R) { 240314564Sdim return !(L == R); 241314564Sdim } 242314564Sdim friend bool operator!=(const_pointer L, const MachineInstrBundleIterator &R) { 243314564Sdim return !(L == R); 244314564Sdim } 245314564Sdim friend bool operator!=(const MachineInstrBundleIterator &L, 246314564Sdim const_reference R) { 247314564Sdim return !(L == R); 248314564Sdim } 249314564Sdim friend bool operator!=(const_reference L, 250314564Sdim const MachineInstrBundleIterator &R) { 251314564Sdim return !(L == R); 252314564Sdim } 253314564Sdim 254303231Sdim // Increment and decrement operators... 255303231Sdim MachineInstrBundleIterator &operator--() { 256314564Sdim this->decrement(MII); 257303231Sdim return *this; 258303231Sdim } 259303231Sdim MachineInstrBundleIterator &operator++() { 260314564Sdim this->increment(MII); 261303231Sdim return *this; 262303231Sdim } 263303231Sdim MachineInstrBundleIterator operator--(int) { 264303231Sdim MachineInstrBundleIterator Temp = *this; 265303231Sdim --*this; 266303231Sdim return Temp; 267303231Sdim } 268303231Sdim MachineInstrBundleIterator operator++(int) { 269303231Sdim MachineInstrBundleIterator Temp = *this; 270303231Sdim ++*this; 271303231Sdim return Temp; 272303231Sdim } 273303231Sdim 274303231Sdim instr_iterator getInstrIterator() const { return MII; } 275314564Sdim 276314564Sdim nonconst_iterator getNonConstIterator() const { return MII.getNonConst(); } 277314564Sdim 278314564Sdim /// Get a reverse iterator to the same node. 279314564Sdim /// 280314564Sdim /// Gives a reverse iterator that will dereference (and have a handle) to the 281314564Sdim /// same node. Converting the endpoint iterators in a range will give a 282314564Sdim /// different range; for range operations, use the explicit conversions. 283314564Sdim reverse_iterator getReverse() const { return MII.getReverse(); } 284303231Sdim}; 285303231Sdim 286303231Sdim} // end namespace llvm 287303231Sdim 288321369Sdim#endif // LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H 289