Index: include/llvm/IR/User.h =================================================================== --- include/llvm/IR/User.h +++ include/llvm/IR/User.h @@ -18,6 +18,7 @@ #ifndef LLVM_IR_USER_H #define LLVM_IR_USER_H +#include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Use.h" @@ -329,6 +330,70 @@ } }; +//===--------------------------------------------------------------------===// +// GraphTraits specializations for def-use graphs +//===--------------------------------------------------------------------===// + +template <> struct GraphTraits { + using NodeRef = Value *; + using ChildIteratorType = User::op_iterator; + + static NodeRef getEntryNode(Value *V) { return V; } + + static ChildIteratorType child_begin(NodeRef N) { + if (auto *U = dyn_cast(N)) + return U->op_begin(); + else + return {}; + } + + static ChildIteratorType child_end(NodeRef N) { + if (auto *U = dyn_cast(N)) + return U->op_end(); + else + return {}; + } +}; + +template <> struct GraphTraits { + using NodeRef = const Value *; + using ChildIteratorType = User::const_op_iterator; + + static NodeRef getEntryNode(const Value *V) { return V; } + + static ChildIteratorType child_begin(NodeRef N) { + if (auto *U = dyn_cast(N)) + return U->op_begin(); + else + return {}; + } + + static ChildIteratorType child_end(NodeRef N) { + if (auto *U = dyn_cast(N)) + return U->op_end(); + else + return {}; + } +}; + +template <> struct GraphTraits> { + using NodeRef = Value *; + using ChildIteratorType = Value::user_iterator; + + static NodeRef getEntryNode(Inverse G) { return G.Graph; } + static ChildIteratorType child_begin(NodeRef N) { return N->user_begin(); } + static ChildIteratorType child_end(NodeRef N) { return N->user_end(); } +}; + +template <> struct GraphTraits> { + using NodeRef = const Value *; + using ChildIteratorType = Value::const_user_iterator; + + static NodeRef getEntryNode(Inverse G) { return G.Graph; } + static ChildIteratorType child_begin(NodeRef N) { return N->user_begin(); } + static ChildIteratorType child_end(NodeRef N) { return N->user_end(); } +}; + } // end namespace llvm #endif // LLVM_IR_USER_H Index: unittests/IR/UserTest.cpp =================================================================== --- unittests/IR/UserTest.cpp +++ unittests/IR/UserTest.cpp @@ -7,11 +7,15 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/User.h" +#include "llvm/ADT/GraphTraits.h" #include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Value.h" #include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" using namespace llvm; @@ -141,4 +145,55 @@ EXPECT_TRUE(TestF->user_empty()); } +TEST(UserTest, GraphTraits) { + LLVMContext C; + const char *ModuleString = "define void @f(i32 %x) {\n" + "entry:\n" + " %0 = icmp eq i32 %x, 1\n" + " br i1 %0, label %1, label %1\n" + "\n" + " ret void\n" + "}\n"; + SMDiagnostic Err; + std::unique_ptr M = parseAssemblyString(ModuleString, Err, C); + + Function *F = M->getFunction("f"); + + Value *Arg = F->arg_begin(); + EXPECT_EQ(std::next(inverse_children(Arg).begin()), + inverse_children(Arg).end()); + + auto *ICmp = dyn_cast(*inverse_children(Arg).begin()); + EXPECT_TRUE(ICmp); + EXPECT_EQ(ICmp->getOpcode(), Instruction::ICmp); + EXPECT_EQ(std::next(children(ICmp).begin(), 2), + children(ICmp).end()); + EXPECT_EQ(*children(ICmp).begin(), Arg); + EXPECT_EQ(std::next(inverse_children(ICmp).begin()), + inverse_children(ICmp).end()); + + auto *One = + dyn_cast(*std::next(children(ICmp).begin())); + EXPECT_TRUE(One); + EXPECT_EQ(One->getSExtValue(), 1); + + auto *Br = dyn_cast(*inverse_children(ICmp).begin()); + EXPECT_TRUE(Br); + EXPECT_EQ(std::next(children(Br).begin(), 3), + children(Br).end()); + EXPECT_EQ(*children(Br).begin(), ICmp); + EXPECT_EQ(*std::next(children(Br).begin()), + *std::next(children(Br).begin(), 2)); + EXPECT_EQ(inverse_children(Br).begin(), + inverse_children(Br).end()); + + auto *BB = dyn_cast(*std::next(children(Br).begin())); + EXPECT_TRUE(BB); + EXPECT_EQ(children(BB).begin(), children(BB).end()); + EXPECT_EQ(std::next(inverse_children(BB).begin(), 2), + inverse_children(BB).end()); + EXPECT_EQ(*inverse_children(BB).begin(), Br); + EXPECT_EQ(*std::next(inverse_children(BB).begin()), Br); +} + } // end anonymous namespace