<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Fri, May 26, 2017 at 5:10 AM, Chandler Carruth via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank" class="cremed">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: chandlerc<br>
Date: Thu May 25 22:10:00 2017<br>
New Revision: 303964<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=303964&view=rev" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-<wbr>project?rev=303964&view=rev</a><br>
Log:<br>
[IR] Add an iterator and range accessor for the PHI nodes of a basic<br>
block.<br>
<br>
This allows writing much more natural and readable range based for loops<br>
directly over the PHI nodes. It also takes advantage of the same tricks<br>
for terminating the sequence as the hand coded versions.<br>
<br>
I've replaced one example of this mostly to showcase the difference and<br>
I've added a unit test to make sure the facilities really work the way<br>
they're intended. I want to use this inside of SimpleLoopUnswitch but it<br>
seems generally nice.<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D33533" rel="noreferrer" target="_blank" class="cremed">https://reviews.llvm.org/<wbr>D33533</a><br>
<br>
Added:<br>
llvm/trunk/unittests/IR/<wbr>BasicBlockTest.cpp<br>
Modified:<br>
llvm/trunk/include/llvm/IR/<wbr>BasicBlock.h<br>
llvm/trunk/lib/IR/BasicBlock.<wbr>cpp<br>
llvm/trunk/unittests/IR/<wbr>CMakeLists.txt<br>
<br>
Modified: llvm/trunk/include/llvm/IR/<wbr>BasicBlock.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/BasicBlock.h?rev=303964&r1=303963&r2=303964&view=diff" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/include/<wbr>llvm/IR/BasicBlock.h?rev=<wbr>303964&r1=303963&r2=303964&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/include/llvm/IR/<wbr>BasicBlock.h (original)<br>
+++ llvm/trunk/include/llvm/IR/<wbr>BasicBlock.h Thu May 25 22:10:00 2017<br>
@@ -33,6 +33,7 @@ class Function;<br>
class LandingPadInst;<br>
class LLVMContext;<br>
class Module;<br>
+class PHINode;<br>
class TerminatorInst;<br>
class ValueSymbolTable;<br>
<br>
@@ -261,6 +262,50 @@ public:<br>
inline const Instruction &back() const { return InstList.back(); }<br>
inline Instruction &back() { return InstList.back(); }<br>
<br>
+ /// Iterator to walk just the phi nodes in the basic block.<br>
+ template <typename PHINodeT = PHINode, typename BBIteratorT = iterator><br>
+ class phi_iterator_impl<br>
+ : public iterator_facade_base<phi_<wbr>iterator_impl<PHINodeT, BBIteratorT>,<br>
+ std::forward_iterator_tag, PHINodeT> {<br>
+ friend BasicBlock;<br>
+<br>
+ PHINodeT *PN;<br>
+<br>
+ phi_iterator_impl(PHINodeT *PN) : PN(PN) {}<br>
+<br>
+ public:<br>
+ // Allow default construction to build variables, but this doesn't build<br>
+ // a useful iterator.<br>
+ phi_iterator_impl() = default;<br>
+<br>
+ // Allow conversion between instantiations where valid.<br>
+ template <typename PHINodeU, typename BBIteratorU><br>
+ phi_iterator_impl(const phi_iterator_impl<PHINodeU, BBIteratorU> &Arg)<br>
+ : PN(Arg.PN) {}<br>
+<br>
+ bool operator==(const phi_iterator_impl &Arg) const { return PN == Arg.PN; }<br>
+<br>
+ PHINodeT &operator*() const { return *PN; }<br>
+<br>
+ using phi_iterator_impl::iterator_<wbr>facade_base::operator++;<br>
+ phi_iterator_impl &operator++() {<br>
+ assert(PN && "Cannot increment the end iterator!");<br>
+ PN = dyn_cast<PHINodeT>(std::next(<wbr>BBIteratorT(PN)));<br>
+ return *this;<br>
+ }<br>
+ };<br>
+ typedef phi_iterator_impl<> phi_iterator;<br>
+ typedef phi_iterator_impl<const PHINode, BasicBlock::const_iterator><br>
+ const_phi_iterator;<br>
+<br>
+ /// Returns a range that iterates over the phis in the basic block.<br>
+ ///<br>
+ /// Note that this cannot be used with basic blocks that have no terminator.<br>
+ iterator_range<const_phi_<wbr>iterator> phis() const {<br>
+ return const_cast<BasicBlock *>(this)->phis();<br>
+ }<br>
+ iterator_range<phi_iterator> phis();<br>
+<br>
/// \brief Return the underlying instruction list container.<br>
///<br>
/// Currently you need to access the underlying instruction list container<br>
<br>
Modified: llvm/trunk/lib/IR/BasicBlock.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/BasicBlock.cpp?rev=303964&r1=303963&r2=303964&view=diff" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/lib/IR/<wbr>BasicBlock.cpp?rev=303964&r1=<wbr>303963&r2=303964&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/IR/BasicBlock.<wbr>cpp (original)<br>
+++ llvm/trunk/lib/IR/BasicBlock.<wbr>cpp Thu May 25 22:10:00 2017<br>
@@ -263,6 +263,10 @@ const BasicBlock *BasicBlock::getUniqueS<br>
return SuccBB;<br>
}<br>
<br>
+iterator_range<BasicBlock::<wbr>phi_iterator> BasicBlock::phis() {<br>
+ return make_range<phi_iterator>(dyn_<wbr>cast<PHINode>(&front()), nullptr);<br>
+}<br>
+<br>
/// This method is used to notify a BasicBlock that the<br>
/// specified Predecessor of the block is no longer able to reach it. This is<br>
/// actually not used to update the Predecessor list, but is actually used to<br>
@@ -389,13 +393,11 @@ BasicBlock *BasicBlock::splitBasicBlock(<br>
// Loop over any phi nodes in the basic block, updating the BB field of<br>
// incoming values...<br>
BasicBlock *Successor = *I;<br>
- PHINode *PN;<br>
- for (BasicBlock::iterator II = Successor->begin();<br>
- (PN = dyn_cast<PHINode>(II)); ++II) {<br>
- int IDX = PN->getBasicBlockIndex(this);<br>
- while (IDX != -1) {<br>
- PN->setIncomingBlock((<wbr>unsigned)IDX, New);<br>
- IDX = PN->getBasicBlockIndex(this);<br>
+ for (auto &PN : Successor->phis()) {<br>
+ int Idx = PN.getBasicBlockIndex(this);<br>
+ while (Idx != -1) {<br>
+ PN.setIncomingBlock((unsigned)<wbr>Idx, New);<br>
+ Idx = PN.getBasicBlockIndex(this);<br>
}<br>
}<br>
}<br>
<br>
Added: llvm/trunk/unittests/IR/<wbr>BasicBlockTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/BasicBlockTest.cpp?rev=303964&view=auto" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/unittests/<wbr>IR/BasicBlockTest.cpp?rev=<wbr>303964&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/unittests/IR/<wbr>BasicBlockTest.cpp (added)<br>
+++ llvm/trunk/unittests/IR/<wbr>BasicBlockTest.cpp Thu May 25 22:10:00 2017<br>
@@ -0,0 +1,75 @@<br>
+//===- llvm/unittest/IR/<wbr>BasicBlockTest.cpp - BasicBlock unit tests --------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#include "llvm/IR/BasicBlock.h"<br>
+#include "llvm/ADT/STLExtras.h"<br>
+#include "llvm/IR/Function.h"<br>
+#include "llvm/IR/IRBuilder.h"<br>
+#include "llvm/IR/LLVMContext.h"<br>
+#include "llvm/IR/Module.h"<br>
+#include "llvm/IR/NoFolder.h"<br>
+#include "gmock/gmock-matchers.h"<br>
+#include "gtest/gtest.h"<br>
+#include <memory><br>
+<br>
+namespace llvm {<br>
+namespace {<br>
+<br>
+TEST(BasicBlockTest, PhiRange) {<br>
+ LLVMContext Context;<br>
+<br>
+ // Create the main block.<br>
+ std::unique_ptr<BasicBlock> BB(BasicBlock::Create(Context)<wbr>);<br>
+<br>
+ // Create some predecessors of it.<br>
+ std::unique_ptr<BasicBlock> BB1(BasicBlock::Create(<wbr>Context));<br>
+ BranchInst::Create(BB.get(), BB1.get());<br>
+ std::unique_ptr<BasicBlock> BB2(BasicBlock::Create(<wbr>Context));<br>
+ BranchInst::Create(BB.get(), BB2.get());<br>
+<br>
+ // Make it a cycle.<br>
+ auto *BI = BranchInst::Create(BB.get(), BB.get());<br>
+<br>
+ // Now insert some PHI nodes.<br>
+ auto *Int32Ty = Type::getInt32Ty(Context);<br>
+ auto *P1 = PHINode::Create(Int32Ty, /*NumReservedValues*/ 3, "phi.1", BI);<br>
+ auto *P2 = PHINode::Create(Int32Ty, /*NumReservedValues*/ 3, "phi.2", BI);<br>
+ auto *P3 = PHINode::Create(Int32Ty, /*NumReservedValues*/ 3, "phi.3", BI);<br>
+<br>
+ // Some non-PHI nodes.<br>
+ auto *Sum = BinaryOperator::CreateAdd(P1, P2, "sum", BI);<br>
+<br>
+ // Now wire up the incoming values that are interesting.<br>
+ P1->addIncoming(P2, BB.get());<br>
+ P2->addIncoming(P1, BB.get());<br>
+ P3->addIncoming(Sum, BB.get());<br>
+<br>
+ // Finally, let's iterate them, which is the thing we're trying to test.<br>
+ // We'll use this to wire up the rest of the incoming values.<br>
+ for (auto &PN : BB->phis()) {<br>
+ PN.addIncoming(UndefValue::<wbr>get(Int32Ty), BB1.get());<br>
+ PN.addIncoming(UndefValue::<wbr>get(Int32Ty), BB2.get());<br>
+ }<br>
+<br>
+ // Test that we can use const iterators and generally that the iterators<br>
+ // behave like iterators.<br>
+ BasicBlock::const_phi_iterator CI;<br>
+ CI = CI = BB->phis().begin();<br></blockquote><div><br></div><div>Is this intentional? It seems to trigger GCC's -Wsequence-point.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+ EXPECT_NE(CI, BB->phis().end());<br>
+<br>
+ // And iterate a const range.<br>
+ for (const auto &PN : const_cast<const BasicBlock *>(BB.get())->phis()) {<br>
+ EXPECT_EQ(BB.get(), PN.getIncomingBlock(0));<br>
+ EXPECT_EQ(BB1.get(), PN.getIncomingBlock(1));<br>
+ EXPECT_EQ(BB2.get(), PN.getIncomingBlock(2));<br>
+ }<br>
+}<br>
+<br>
+} // End anonymous namespace.<br>
+} // End llvm namespace.<br>
<br>
Modified: llvm/trunk/unittests/IR/<wbr>CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/CMakeLists.txt?rev=303964&r1=303963&r2=303964&view=diff" rel="noreferrer" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/unittests/<wbr>IR/CMakeLists.txt?rev=303964&<wbr>r1=303963&r2=303964&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/unittests/IR/<wbr>CMakeLists.txt (original)<br>
+++ llvm/trunk/unittests/IR/<wbr>CMakeLists.txt Thu May 25 22:10:00 2017<br>
@@ -8,6 +8,7 @@ set(LLVM_LINK_COMPONENTS<br>
set(IRSources<br>
AsmWriterTest.cpp<br>
AttributesTest.cpp<br>
+ BasicBlockTest.cpp<br>
ConstantRangeTest.cpp<br>
ConstantsTest.cpp<br>
DebugInfoTest.cpp<br>
<br>
<br>
______________________________<wbr>_________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" class="cremed">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank" class="cremed">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>