Bug Summary

File:llvm/lib/Target/Hexagon/HexagonCFGOptimizer.cpp
Warning:line 196, column 26
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name HexagonCFGOptimizer.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/lib/Target/Hexagon -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/lib/Target/Hexagon -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/lib/Target/Hexagon -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/include -D NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/lib/Target/Hexagon -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e=. -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2021-09-04-040900-46481-1 -x c++ /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/lib/Target/Hexagon/HexagonCFGOptimizer.cpp

/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/lib/Target/Hexagon/HexagonCFGOptimizer.cpp

1//===- HexagonCFGOptimizer.cpp - CFG optimizations ------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Hexagon.h"
10#include "MCTargetDesc/HexagonMCTargetDesc.h"
11#include "llvm/CodeGen/MachineBasicBlock.h"
12#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
13#include "llvm/CodeGen/MachineFunction.h"
14#include "llvm/CodeGen/MachineFunctionPass.h"
15#include "llvm/CodeGen/MachineInstr.h"
16#include "llvm/CodeGen/MachineOperand.h"
17#include "llvm/CodeGen/TargetInstrInfo.h"
18#include "llvm/CodeGen/TargetSubtargetInfo.h"
19#include "llvm/Pass.h"
20#include "llvm/Support/ErrorHandling.h"
21#include <cassert>
22#include <vector>
23
24using namespace llvm;
25
26#define DEBUG_TYPE"hexagon_cfg" "hexagon_cfg"
27
28namespace llvm {
29
30FunctionPass *createHexagonCFGOptimizer();
31void initializeHexagonCFGOptimizerPass(PassRegistry&);
32
33} // end namespace llvm
34
35namespace {
36
37class HexagonCFGOptimizer : public MachineFunctionPass {
38private:
39 void InvertAndChangeJumpTarget(MachineInstr &, MachineBasicBlock *);
40 bool isOnFallThroughPath(MachineBasicBlock *MBB);
41
42public:
43 static char ID;
44
45 HexagonCFGOptimizer() : MachineFunctionPass(ID) {
46 initializeHexagonCFGOptimizerPass(*PassRegistry::getPassRegistry());
47 }
48
49 StringRef getPassName() const override { return "Hexagon CFG Optimizer"; }
50 bool runOnMachineFunction(MachineFunction &Fn) override;
51
52 MachineFunctionProperties getRequiredProperties() const override {
53 return MachineFunctionProperties().set(
54 MachineFunctionProperties::Property::NoVRegs);
55 }
56};
57
58} // end anonymous namespace
59
60char HexagonCFGOptimizer::ID = 0;
61
62static bool IsConditionalBranch(int Opc) {
63 switch (Opc) {
20
Control jumps to 'case J2_jumpfnewpt:' at line 71
64 case Hexagon::J2_jumpt:
65 case Hexagon::J2_jumptpt:
66 case Hexagon::J2_jumpf:
67 case Hexagon::J2_jumpfpt:
68 case Hexagon::J2_jumptnew:
69 case Hexagon::J2_jumpfnew:
70 case Hexagon::J2_jumptnewpt:
71 case Hexagon::J2_jumpfnewpt:
72 return true;
21
Returning the value 1, which participates in a condition later
73 }
74 return false;
75}
76
77static bool IsUnconditionalJump(int Opc) {
78 return (Opc == Hexagon::J2_jump);
34
Assuming 'Opc' is equal to J2_jump
35
Returning the value 1, which participates in a condition later
79}
80
81void HexagonCFGOptimizer::InvertAndChangeJumpTarget(
82 MachineInstr &MI, MachineBasicBlock *NewTarget) {
83 const TargetInstrInfo *TII =
84 MI.getParent()->getParent()->getSubtarget().getInstrInfo();
85 int NewOpcode = 0;
86 switch (MI.getOpcode()) {
87 case Hexagon::J2_jumpt:
88 NewOpcode = Hexagon::J2_jumpf;
89 break;
90 case Hexagon::J2_jumpf:
91 NewOpcode = Hexagon::J2_jumpt;
92 break;
93 case Hexagon::J2_jumptnewpt:
94 NewOpcode = Hexagon::J2_jumpfnewpt;
95 break;
96 case Hexagon::J2_jumpfnewpt:
97 NewOpcode = Hexagon::J2_jumptnewpt;
98 break;
99 default:
100 llvm_unreachable("Cannot handle this case")__builtin_unreachable();
101 }
102
103 MI.setDesc(TII->get(NewOpcode));
104 MI.getOperand(1).setMBB(NewTarget);
105}
106
107bool HexagonCFGOptimizer::isOnFallThroughPath(MachineBasicBlock *MBB) {
108 if (MBB->canFallThrough())
109 return true;
110 for (MachineBasicBlock *PB : MBB->predecessors())
111 if (PB->isLayoutSuccessor(MBB) && PB->canFallThrough())
112 return true;
113 return false;
114}
115
116bool HexagonCFGOptimizer::runOnMachineFunction(MachineFunction &Fn) {
117 if (skipFunction(Fn.getFunction()))
1
Assuming the condition is false
2
Taking false branch
118 return false;
119
120 // Loop over all of the basic blocks.
121 for (MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end();
7
Loop condition is true. Entering loop body
122 MBBb != MBBe; ++MBBb) {
3
Calling 'operator!='
6
Returning from 'operator!='
123 MachineBasicBlock *MBB = &*MBBb;
124
125 // Traverse the basic block.
126 MachineBasicBlock::iterator MII = MBB->getFirstTerminator();
127 if (MII != MBB->end()) {
8
Calling 'operator!='
17
Returning from 'operator!='
18
Taking true branch
128 MachineInstr &MI = *MII;
129 int Opc = MI.getOpcode();
130 if (IsConditionalBranch(Opc)) {
19
Calling 'IsConditionalBranch'
22
Returning from 'IsConditionalBranch'
23
Taking true branch
131 // (Case 1) Transform the code if the following condition occurs:
132 // BB1: if (p0) jump BB3
133 // ...falls-through to BB2 ...
134 // BB2: jump BB4
135 // ...next block in layout is BB3...
136 // BB3: ...
137 //
138 // Transform this to:
139 // BB1: if (!p0) jump BB4
140 // Remove BB2
141 // BB3: ...
142 //
143 // (Case 2) A variation occurs when BB3 contains a JMP to BB4:
144 // BB1: if (p0) jump BB3
145 // ...falls-through to BB2 ...
146 // BB2: jump BB4
147 // ...other basic blocks ...
148 // BB4:
149 // ...not a fall-thru
150 // BB3: ...
151 // jump BB4
152 //
153 // Transform this to:
154 // BB1: if (!p0) jump BB4
155 // Remove BB2
156 // BB3: ...
157 // BB4: ...
158 unsigned NumSuccs = MBB->succ_size();
159 MachineBasicBlock::succ_iterator SI = MBB->succ_begin();
160 MachineBasicBlock* FirstSucc = *SI;
161 MachineBasicBlock* SecondSucc = *(++SI);
24
'SecondSucc' initialized here
162 MachineBasicBlock* LayoutSucc = nullptr;
163 MachineBasicBlock* JumpAroundTarget = nullptr;
164
165 if (MBB->isLayoutSuccessor(FirstSucc)) {
25
Assuming the condition is true
26
Taking true branch
166 LayoutSucc = FirstSucc;
167 JumpAroundTarget = SecondSucc;
27
The value of 'SecondSucc' is assigned to 'JumpAroundTarget'
168 } else if (MBB->isLayoutSuccessor(SecondSucc)) {
169 LayoutSucc = SecondSucc;
170 JumpAroundTarget = FirstSucc;
171 } else {
172 // Odd case...cannot handle.
173 }
174
175 // The target of the unconditional branch must be JumpAroundTarget.
176 // TODO: If not, we should not invert the unconditional branch.
177 MachineBasicBlock* CondBranchTarget = nullptr;
178 if (MI.getOpcode() == Hexagon::J2_jumpt ||
179 MI.getOpcode() == Hexagon::J2_jumpf) {
180 CondBranchTarget = MI.getOperand(1).getMBB();
181 }
182
183 if (!LayoutSucc || (CondBranchTarget != JumpAroundTarget)) {
28
Assuming 'LayoutSucc' is non-null
29
Assuming 'CondBranchTarget' is equal to 'JumpAroundTarget'
184 continue;
185 }
186
187 if ((NumSuccs == 2) && LayoutSucc
30.1
'LayoutSucc' is non-null
30.1
'LayoutSucc' is non-null
30.1
'LayoutSucc' is non-null
&& (LayoutSucc->pred_size() == 1)) {
30
Assuming 'NumSuccs' is equal to 2
31
Assuming the condition is true
188 // Ensure that BB2 has one instruction -- an unconditional jump.
189 if ((LayoutSucc->size() == 1) &&
32
Assuming the condition is true
37
Taking true branch
190 IsUnconditionalJump(LayoutSucc->front().getOpcode())) {
33
Calling 'IsUnconditionalJump'
36
Returning from 'IsUnconditionalJump'
191 assert(JumpAroundTarget && "jump target is needed to process second basic block")(static_cast<void> (0));
192 MachineBasicBlock* UncondTarget =
193 LayoutSucc->front().getOperand(0).getMBB();
194 // Check if the layout successor of BB2 is BB3.
195 bool case1 = LayoutSucc->isLayoutSuccessor(JumpAroundTarget);
196 bool case2 = JumpAroundTarget->isSuccessor(UncondTarget) &&
38
Called C++ object pointer is null
197 !JumpAroundTarget->empty() &&
198 IsUnconditionalJump(JumpAroundTarget->back().getOpcode()) &&
199 JumpAroundTarget->pred_size() == 1 &&
200 JumpAroundTarget->succ_size() == 1;
201
202 if (case1 || case2) {
203 InvertAndChangeJumpTarget(MI, UncondTarget);
204 MBB->replaceSuccessor(JumpAroundTarget, UncondTarget);
205
206 // Remove the unconditional branch in LayoutSucc.
207 LayoutSucc->erase(LayoutSucc->begin());
208 LayoutSucc->replaceSuccessor(UncondTarget, JumpAroundTarget);
209
210 // This code performs the conversion for case 2, which moves
211 // the block to the fall-thru case (BB3 in the code above).
212 if (case2 && !case1) {
213 JumpAroundTarget->moveAfter(LayoutSucc);
214 // only move a block if it doesn't have a fall-thru. otherwise
215 // the CFG will be incorrect.
216 if (!isOnFallThroughPath(UncondTarget))
217 UncondTarget->moveAfter(JumpAroundTarget);
218 }
219
220 // Correct live-in information. Is used by post-RA scheduler
221 // The live-in to LayoutSucc is now all values live-in to
222 // JumpAroundTarget.
223 std::vector<MachineBasicBlock::RegisterMaskPair> OrigLiveIn(
224 LayoutSucc->livein_begin(), LayoutSucc->livein_end());
225 std::vector<MachineBasicBlock::RegisterMaskPair> NewLiveIn(
226 JumpAroundTarget->livein_begin(),
227 JumpAroundTarget->livein_end());
228 for (const auto &OrigLI : OrigLiveIn)
229 LayoutSucc->removeLiveIn(OrigLI.PhysReg);
230 for (const auto &NewLI : NewLiveIn)
231 LayoutSucc->addLiveIn(NewLI);
232 }
233 }
234 }
235 }
236 }
237 }
238 return true;
239}
240
241//===----------------------------------------------------------------------===//
242// Public Constructor Functions
243//===----------------------------------------------------------------------===//
244
245INITIALIZE_PASS(HexagonCFGOptimizer, "hexagon-cfg", "Hexagon CFG Optimizer",static void *initializeHexagonCFGOptimizerPassOnce(PassRegistry
&Registry) { PassInfo *PI = new PassInfo( "Hexagon CFG Optimizer"
, "hexagon-cfg", &HexagonCFGOptimizer::ID, PassInfo::NormalCtor_t
(callDefaultCtor<HexagonCFGOptimizer>), false, false); Registry
.registerPass(*PI, true); return PI; } static llvm::once_flag
InitializeHexagonCFGOptimizerPassFlag; void llvm::initializeHexagonCFGOptimizerPass
(PassRegistry &Registry) { llvm::call_once(InitializeHexagonCFGOptimizerPassFlag
, initializeHexagonCFGOptimizerPassOnce, std::ref(Registry));
}
246 false, false)static void *initializeHexagonCFGOptimizerPassOnce(PassRegistry
&Registry) { PassInfo *PI = new PassInfo( "Hexagon CFG Optimizer"
, "hexagon-cfg", &HexagonCFGOptimizer::ID, PassInfo::NormalCtor_t
(callDefaultCtor<HexagonCFGOptimizer>), false, false); Registry
.registerPass(*PI, true); return PI; } static llvm::once_flag
InitializeHexagonCFGOptimizerPassFlag; void llvm::initializeHexagonCFGOptimizerPass
(PassRegistry &Registry) { llvm::call_once(InitializeHexagonCFGOptimizerPassFlag
, initializeHexagonCFGOptimizerPassOnce, std::ref(Registry));
}
247
248FunctionPass *llvm::createHexagonCFGOptimizer() {
249 return new HexagonCFGOptimizer();
250}

/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/include/llvm/ADT/ilist_iterator.h

1//===- llvm/ADT/ilist_iterator.h - Intrusive List Iterator ------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_ADT_ILIST_ITERATOR_H
10#define LLVM_ADT_ILIST_ITERATOR_H
11
12#include "llvm/ADT/ilist_node.h"
13#include <cassert>
14#include <cstddef>
15#include <iterator>
16#include <type_traits>
17
18namespace llvm {
19
20namespace ilist_detail {
21
22/// Find const-correct node types.
23template <class OptionsT, bool IsConst> struct IteratorTraits;
24template <class OptionsT> struct IteratorTraits<OptionsT, false> {
25 using value_type = typename OptionsT::value_type;
26 using pointer = typename OptionsT::pointer;
27 using reference = typename OptionsT::reference;
28 using node_pointer = ilist_node_impl<OptionsT> *;
29 using node_reference = ilist_node_impl<OptionsT> &;
30};
31template <class OptionsT> struct IteratorTraits<OptionsT, true> {
32 using value_type = const typename OptionsT::value_type;
33 using pointer = typename OptionsT::const_pointer;
34 using reference = typename OptionsT::const_reference;
35 using node_pointer = const ilist_node_impl<OptionsT> *;
36 using node_reference = const ilist_node_impl<OptionsT> &;
37};
38
39template <bool IsReverse> struct IteratorHelper;
40template <> struct IteratorHelper<false> : ilist_detail::NodeAccess {
41 using Access = ilist_detail::NodeAccess;
42
43 template <class T> static void increment(T *&I) { I = Access::getNext(*I); }
44 template <class T> static void decrement(T *&I) { I = Access::getPrev(*I); }
45};
46template <> struct IteratorHelper<true> : ilist_detail::NodeAccess {
47 using Access = ilist_detail::NodeAccess;
48
49 template <class T> static void increment(T *&I) { I = Access::getPrev(*I); }
50 template <class T> static void decrement(T *&I) { I = Access::getNext(*I); }
51};
52
53} // end namespace ilist_detail
54
55/// Iterator for intrusive lists based on ilist_node.
56template <class OptionsT, bool IsReverse, bool IsConst>
57class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
58 friend ilist_iterator<OptionsT, IsReverse, !IsConst>;
59 friend ilist_iterator<OptionsT, !IsReverse, IsConst>;
60 friend ilist_iterator<OptionsT, !IsReverse, !IsConst>;
61
62 using Traits = ilist_detail::IteratorTraits<OptionsT, IsConst>;
63 using Access = ilist_detail::SpecificNodeAccess<OptionsT>;
64
65public:
66 using value_type = typename Traits::value_type;
67 using pointer = typename Traits::pointer;
68 using reference = typename Traits::reference;
69 using difference_type = ptrdiff_t;
70 using iterator_category = std::bidirectional_iterator_tag;
71 using const_pointer = typename OptionsT::const_pointer;
72 using const_reference = typename OptionsT::const_reference;
73
74private:
75 using node_pointer = typename Traits::node_pointer;
76 using node_reference = typename Traits::node_reference;
77
78 node_pointer NodePtr = nullptr;
79
80public:
81 /// Create from an ilist_node.
82 explicit ilist_iterator(node_reference N) : NodePtr(&N) {}
83
84 explicit ilist_iterator(pointer NP) : NodePtr(Access::getNodePtr(NP)) {}
85 explicit ilist_iterator(reference NR) : NodePtr(Access::getNodePtr(&NR)) {}
86 ilist_iterator() = default;
87
88 // This is templated so that we can allow constructing a const iterator from
89 // a nonconst iterator...
90 template <bool RHSIsConst>
91 ilist_iterator(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS,
92 std::enable_if_t<IsConst || !RHSIsConst, void *> = nullptr)
93 : NodePtr(RHS.NodePtr) {}
94
95 // This is templated so that we can allow assigning to a const iterator from
96 // a nonconst iterator...
97 template <bool RHSIsConst>
98 std::enable_if_t<IsConst || !RHSIsConst, ilist_iterator &>
99 operator=(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS) {
100 NodePtr = RHS.NodePtr;
101 return *this;
102 }
103
104 /// Explicit conversion between forward/reverse iterators.
105 ///
106 /// Translate between forward and reverse iterators without changing range
107 /// boundaries. The resulting iterator will dereference (and have a handle)
108 /// to the previous node, which is somewhat unexpected; but converting the
109 /// two endpoints in a range will give the same range in reverse.
110 ///
111 /// This matches std::reverse_iterator conversions.
112 explicit ilist_iterator(
113 const ilist_iterator<OptionsT, !IsReverse, IsConst> &RHS)
114 : ilist_iterator(++RHS.getReverse()) {}
115
116 /// Get a reverse iterator to the same node.
117 ///
118 /// Gives a reverse iterator that will dereference (and have a handle) to the
119 /// same node. Converting the endpoint iterators in a range will give a
120 /// different range; for range operations, use the explicit conversions.
121 ilist_iterator<OptionsT, !IsReverse, IsConst> getReverse() const {
122 if (NodePtr)
123 return ilist_iterator<OptionsT, !IsReverse, IsConst>(*NodePtr);
124 return ilist_iterator<OptionsT, !IsReverse, IsConst>();
125 }
126
127 /// Const-cast.
128 ilist_iterator<OptionsT, IsReverse, false> getNonConst() const {
129 if (NodePtr)
130 return ilist_iterator<OptionsT, IsReverse, false>(
131 const_cast<typename ilist_iterator<OptionsT, IsReverse,
132 false>::node_reference>(*NodePtr));
133 return ilist_iterator<OptionsT, IsReverse, false>();
134 }
135
136 // Accessors...
137 reference operator*() const {
138 assert(!NodePtr->isKnownSentinel())(static_cast<void> (0));
139 return *Access::getValuePtr(NodePtr);
140 }
141 pointer operator->() const { return &operator*(); }
142
143 // Comparison operators
144 friend bool operator==(const ilist_iterator &LHS, const ilist_iterator &RHS) {
145 return LHS.NodePtr == RHS.NodePtr;
11
Assuming 'LHS.NodePtr' is not equal to 'RHS.NodePtr'
12
Returning zero, which participates in a condition later
146 }
147 friend bool operator!=(const ilist_iterator &LHS, const ilist_iterator &RHS) {
148 return LHS.NodePtr != RHS.NodePtr;
4
Assuming 'LHS.NodePtr' is not equal to 'RHS.NodePtr'
5
Returning the value 1, which participates in a condition later
149 }
150
151 // Increment and decrement operators...
152 ilist_iterator &operator--() {
153 NodePtr = IsReverse ? NodePtr->getNext() : NodePtr->getPrev();
154 return *this;
155 }
156 ilist_iterator &operator++() {
157 NodePtr = IsReverse ? NodePtr->getPrev() : NodePtr->getNext();
158 return *this;
159 }
160 ilist_iterator operator--(int) {
161 ilist_iterator tmp = *this;
162 --*this;
163 return tmp;
164 }
165 ilist_iterator operator++(int) {
166 ilist_iterator tmp = *this;
167 ++*this;
168 return tmp;
169 }
170
171 /// Get the underlying ilist_node.
172 node_pointer getNodePtr() const { return static_cast<node_pointer>(NodePtr); }
173
174 /// Check for end. Only valid if ilist_sentinel_tracking<true>.
175 bool isEnd() const { return NodePtr ? NodePtr->isSentinel() : false; }
176};
177
178template <typename From> struct simplify_type;
179
180/// Allow ilist_iterators to convert into pointers to a node automatically when
181/// used by the dyn_cast, cast, isa mechanisms...
182///
183/// FIXME: remove this, since there is no implicit conversion to NodeTy.
184template <class OptionsT, bool IsConst>
185struct simplify_type<ilist_iterator<OptionsT, false, IsConst>> {
186 using iterator = ilist_iterator<OptionsT, false, IsConst>;
187 using SimpleType = typename iterator::pointer;
188
189 static SimpleType getSimplifiedValue(const iterator &Node) { return &*Node; }
190};
191template <class OptionsT, bool IsConst>
192struct simplify_type<const ilist_iterator<OptionsT, false, IsConst>>
193 : simplify_type<ilist_iterator<OptionsT, false, IsConst>> {};
194
195} // end namespace llvm
196
197#endif // LLVM_ADT_ILIST_ITERATOR_H

/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/include/llvm/CodeGen/MachineInstrBundleIterator.h

1//===- llvm/CodeGen/MachineInstrBundleIterator.h ----------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Defines an iterator class that bundles MachineInstr.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H
14#define LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H
15
16#include "llvm/ADT/ilist.h"
17#include "llvm/ADT/simple_ilist.h"
18#include <cassert>
19#include <iterator>
20#include <type_traits>
21
22namespace llvm {
23
24template <class T, bool IsReverse> struct MachineInstrBundleIteratorTraits;
25template <class T> struct MachineInstrBundleIteratorTraits<T, false> {
26 using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>;
27 using instr_iterator = typename list_type::iterator;
28 using nonconst_instr_iterator = typename list_type::iterator;
29 using const_instr_iterator = typename list_type::const_iterator;
30};
31template <class T> struct MachineInstrBundleIteratorTraits<T, true> {
32 using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>;
33 using instr_iterator = typename list_type::reverse_iterator;
34 using nonconst_instr_iterator = typename list_type::reverse_iterator;
35 using const_instr_iterator = typename list_type::const_reverse_iterator;
36};
37template <class T> struct MachineInstrBundleIteratorTraits<const T, false> {
38 using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>;
39 using instr_iterator = typename list_type::const_iterator;
40 using nonconst_instr_iterator = typename list_type::iterator;
41 using const_instr_iterator = typename list_type::const_iterator;
42};
43template <class T> struct MachineInstrBundleIteratorTraits<const T, true> {
44 using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>;
45 using instr_iterator = typename list_type::const_reverse_iterator;
46 using nonconst_instr_iterator = typename list_type::reverse_iterator;
47 using const_instr_iterator = typename list_type::const_reverse_iterator;
48};
49
50template <bool IsReverse> struct MachineInstrBundleIteratorHelper;
51template <> struct MachineInstrBundleIteratorHelper<false> {
52 /// Get the beginning of the current bundle.
53 template <class Iterator> static Iterator getBundleBegin(Iterator I) {
54 if (!I.isEnd())
55 while (I->isBundledWithPred())
56 --I;
57 return I;
58 }
59
60 /// Get the final node of the current bundle.
61 template <class Iterator> static Iterator getBundleFinal(Iterator I) {
62 if (!I.isEnd())
63 while (I->isBundledWithSucc())
64 ++I;
65 return I;
66 }
67
68 /// Increment forward ilist iterator.
69 template <class Iterator> static void increment(Iterator &I) {
70 I = std::next(getBundleFinal(I));
71 }
72
73 /// Decrement forward ilist iterator.
74 template <class Iterator> static void decrement(Iterator &I) {
75 I = getBundleBegin(std::prev(I));
76 }
77};
78
79template <> struct MachineInstrBundleIteratorHelper<true> {
80 /// Get the beginning of the current bundle.
81 template <class Iterator> static Iterator getBundleBegin(Iterator I) {
82 return MachineInstrBundleIteratorHelper<false>::getBundleBegin(
83 I.getReverse())
84 .getReverse();
85 }
86
87 /// Get the final node of the current bundle.
88 template <class Iterator> static Iterator getBundleFinal(Iterator I) {
89 return MachineInstrBundleIteratorHelper<false>::getBundleFinal(
90 I.getReverse())
91 .getReverse();
92 }
93
94 /// Increment reverse ilist iterator.
95 template <class Iterator> static void increment(Iterator &I) {
96 I = getBundleBegin(std::next(I));
97 }
98
99 /// Decrement reverse ilist iterator.
100 template <class Iterator> static void decrement(Iterator &I) {
101 I = std::prev(getBundleFinal(I));
102 }
103};
104
105/// MachineBasicBlock iterator that automatically skips over MIs that are
106/// inside bundles (i.e. walk top level MIs only).
107template <typename Ty, bool IsReverse = false>
108class MachineInstrBundleIterator : MachineInstrBundleIteratorHelper<IsReverse> {
109 using Traits = MachineInstrBundleIteratorTraits<Ty, IsReverse>;
110 using instr_iterator = typename Traits::instr_iterator;
111
112 instr_iterator MII;
113
114public:
115 using value_type = typename instr_iterator::value_type;
116 using difference_type = typename instr_iterator::difference_type;
117 using pointer = typename instr_iterator::pointer;
118 using reference = typename instr_iterator::reference;
119 using const_pointer = typename instr_iterator::const_pointer;
120 using const_reference = typename instr_iterator::const_reference;
121 using iterator_category = std::bidirectional_iterator_tag;
122
123private:
124 using nonconst_instr_iterator = typename Traits::nonconst_instr_iterator;
125 using const_instr_iterator = typename Traits::const_instr_iterator;
126 using nonconst_iterator =
127 MachineInstrBundleIterator<typename nonconst_instr_iterator::value_type,
128 IsReverse>;
129 using reverse_iterator = MachineInstrBundleIterator<Ty, !IsReverse>;
130
131public:
132 MachineInstrBundleIterator(instr_iterator MI) : MII(MI) {
133 assert((!MI.getNodePtr() || MI.isEnd() || !MI->isBundledWithPred()) &&(static_cast<void> (0))
134 "It's not legal to initialize MachineInstrBundleIterator with a "(static_cast<void> (0))
135 "bundled MI")(static_cast<void> (0));
136 }
137
138 MachineInstrBundleIterator(reference MI) : MII(MI) {
139 assert(!MI.isBundledWithPred() && "It's not legal to initialize "(static_cast<void> (0))
140 "MachineInstrBundleIterator with a "(static_cast<void> (0))
141 "bundled MI")(static_cast<void> (0));
142 }
143
144 MachineInstrBundleIterator(pointer MI) : MII(MI) {
145 // FIXME: This conversion should be explicit.
146 assert((!MI || !MI->isBundledWithPred()) && "It's not legal to initialize "(static_cast<void> (0))
147 "MachineInstrBundleIterator "(static_cast<void> (0))
148 "with a bundled MI")(static_cast<void> (0));
149 }
150
151 // Template allows conversion from const to nonconst.
152 template <class OtherTy>
153 MachineInstrBundleIterator(
154 const MachineInstrBundleIterator<OtherTy, IsReverse> &I,
155 std::enable_if_t<std::is_convertible<OtherTy *, Ty *>::value, void *> =
156 nullptr)
157 : MII(I.getInstrIterator()) {}
158
159 MachineInstrBundleIterator() : MII(nullptr) {}
160
161 /// Explicit conversion between forward/reverse iterators.
162 ///
163 /// Translate between forward and reverse iterators without changing range
164 /// boundaries. The resulting iterator will dereference (and have a handle)
165 /// to the previous node, which is somewhat unexpected; but converting the
166 /// two endpoints in a range will give the same range in reverse.
167 ///
168 /// This matches std::reverse_iterator conversions.
169 explicit MachineInstrBundleIterator(
170 const MachineInstrBundleIterator<Ty, !IsReverse> &I)
171 : MachineInstrBundleIterator(++I.getReverse()) {}
172
173 /// Get the bundle iterator for the given instruction's bundle.
174 static MachineInstrBundleIterator getAtBundleBegin(instr_iterator MI) {
175 return MachineInstrBundleIteratorHelper<IsReverse>::getBundleBegin(MI);
176 }
177
178 reference operator*() const { return *MII; }
179 pointer operator->() const { return &operator*(); }
180
181 /// Check for null.
182 bool isValid() const { return MII.getNodePtr(); }
183
184 friend bool operator==(const MachineInstrBundleIterator &L,
185 const MachineInstrBundleIterator &R) {
186 return L.MII == R.MII;
10
Calling 'operator=='
13
Returning from 'operator=='
14
Returning zero, which participates in a condition later
187 }
188 friend bool operator==(const MachineInstrBundleIterator &L,
189 const const_instr_iterator &R) {
190 return L.MII == R; // Avoid assertion about validity of R.
191 }
192 friend bool operator==(const const_instr_iterator &L,
193 const MachineInstrBundleIterator &R) {
194 return L == R.MII; // Avoid assertion about validity of L.
195 }
196 friend bool operator==(const MachineInstrBundleIterator &L,
197 const nonconst_instr_iterator &R) {
198 return L.MII == R; // Avoid assertion about validity of R.
199 }
200 friend bool operator==(const nonconst_instr_iterator &L,
201 const MachineInstrBundleIterator &R) {
202 return L == R.MII; // Avoid assertion about validity of L.
203 }
204 friend bool operator==(const MachineInstrBundleIterator &L, const_pointer R) {
205 return L == const_instr_iterator(R); // Avoid assertion about validity of R.
206 }
207 friend bool operator==(const_pointer L, const MachineInstrBundleIterator &R) {
208 return const_instr_iterator(L) == R; // Avoid assertion about validity of L.
209 }
210 friend bool operator==(const MachineInstrBundleIterator &L,
211 const_reference R) {
212 return L == &R; // Avoid assertion about validity of R.
213 }
214 friend bool operator==(const_reference L,
215 const MachineInstrBundleIterator &R) {
216 return &L == R; // Avoid assertion about validity of L.
217 }
218
219 friend bool operator!=(const MachineInstrBundleIterator &L,
220 const MachineInstrBundleIterator &R) {
221 return !(L == R);
9
Calling 'operator=='
15
Returning from 'operator=='
16
Returning the value 1, which participates in a condition later
222 }
223 friend bool operator!=(const MachineInstrBundleIterator &L,
224 const const_instr_iterator &R) {
225 return !(L == R);
226 }
227 friend bool operator!=(const const_instr_iterator &L,
228 const MachineInstrBundleIterator &R) {
229 return !(L == R);
230 }
231 friend bool operator!=(const MachineInstrBundleIterator &L,
232 const nonconst_instr_iterator &R) {
233 return !(L == R);
234 }
235 friend bool operator!=(const nonconst_instr_iterator &L,
236 const MachineInstrBundleIterator &R) {
237 return !(L == R);
238 }
239 friend bool operator!=(const MachineInstrBundleIterator &L, const_pointer R) {
240 return !(L == R);
241 }
242 friend bool operator!=(const_pointer L, const MachineInstrBundleIterator &R) {
243 return !(L == R);
244 }
245 friend bool operator!=(const MachineInstrBundleIterator &L,
246 const_reference R) {
247 return !(L == R);
248 }
249 friend bool operator!=(const_reference L,
250 const MachineInstrBundleIterator &R) {
251 return !(L == R);
252 }
253
254 // Increment and decrement operators...
255 MachineInstrBundleIterator &operator--() {
256 this->decrement(MII);
257 return *this;
258 }
259 MachineInstrBundleIterator &operator++() {
260 this->increment(MII);
261 return *this;
262 }
263 MachineInstrBundleIterator operator--(int) {
264 MachineInstrBundleIterator Temp = *this;
265 --*this;
266 return Temp;
267 }
268 MachineInstrBundleIterator operator++(int) {
269 MachineInstrBundleIterator Temp = *this;
270 ++*this;
271 return Temp;
272 }
273
274 instr_iterator getInstrIterator() const { return MII; }
275
276 nonconst_iterator getNonConstIterator() const { return MII.getNonConst(); }
277
278 /// Get a reverse iterator to the same node.
279 ///
280 /// Gives a reverse iterator that will dereference (and have a handle) to the
281 /// same node. Converting the endpoint iterators in a range will give a
282 /// different range; for range operations, use the explicit conversions.
283 reverse_iterator getReverse() const { return MII.getReverse(); }
284};
285
286} // end namespace llvm
287
288#endif // LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H