<div dir="ltr">Please do!</div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Feb 8, 2017 at 5:06 AM, Alexander Kornienko <span dir="ltr"><<a href="mailto:alexfh@google.com" target="_blank">alexfh@google.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><div class="h5">On Tue, Feb 7, 2017 at 10:10 PM, Daniel Berlin via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: dannyb<br>
Date: Tue Feb  7 15:10:46 2017<br>
New Revision: 294351<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=294351&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject?rev=294351&view=rev</a><br>
Log:<br>
Add PredicateInfo utility and printing pass<br>
<br>
Summary:<br>
This patch adds a utility to build extended SSA (see "ABCD: eliminating<br>
array bounds checks on demand"), and an intrinsic to support it. This<br>
is then used to get functionality equivalent to propagateEquality in<br>
GVN, in NewGVN (without having to replace instructions as we go). It<br>
would work similarly in SCCP or other passes. This has been talked<br>
about a few times, so i built a real implementation and tried to<br>
productionize it.<br>
<br>
Copies are inserted for operands used in assumes and conditional<br>
branches that are based on comparisons (see below for more)<br>
<br>
Every use affected by the predicate is renamed to the appropriate<br>
intrinsic result.<br>
<br>
E.g.<br>
%cmp = icmp eq i32 %x, 50<br>
br i1 %cmp, label %true, label %false<br>
true:<br>
ret i32 %x<br>
false:<br>
ret i32 1<br>
<br>
will become<br>
<br>
%cmp = icmp eq i32, %x, 50<br>
br i1 %cmp, label %true, label %false<br>
true:<br>
; Has predicate info<br>
; branch predicate info { TrueEdge: 1 Comparison: %cmp = icmp eq i32 %x, 50 }<br>
%x.0 = call @llvm.ssa_copy.i32(i32 %x)<br>
ret i32 %x.0<br>
false:<br>
ret i23 1<br>
<br>
(you can use -print-predicateinfo to get an annotated-with-predicateinfo dump)<br>
<br>
This enables us to easily determine what operations are affected by a<br>
given predicate, and how operations affected by a chain of<br>
predicates.<br>
<br>
Reviewers: davide, sanjoy<br>
<br>
Subscribers: mgorny, llvm-commits, Prazek<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D29519" rel="noreferrer" target="_blank">https://reviews.llvm.org/D2951<wbr>9</a><br>
<br>
Update for review comments<br>
<br>
Fix a bug Nuno noticed where we are giving information about and/or on edges where the info is not useful and easy to use wrong<br>
<br>
Update for review comments<br>
<br>
Added:<br>
    llvm/trunk/include/llvm/Transf<wbr>orms/Utils/PredicateInfo.h<br>
    llvm/trunk/lib/Transforms/Util<wbr>s/PredicateInfo.cpp<br>
    llvm/trunk/test/Transforms/Uti<wbr>l/PredicateInfo/<br>
    llvm/trunk/test/Transforms/Uti<wbr>l/PredicateInfo/condprop.ll<br>
    llvm/trunk/test/Transforms/Uti<wbr>l/PredicateInfo/testandor.ll<br>
Modified:<br>
    llvm/trunk/include/llvm/Initia<wbr>lizePasses.h<br>
    llvm/trunk/lib/Passes/PassBuil<wbr>der.cpp<br>
    llvm/trunk/lib/Transforms/Util<wbr>s/CMakeLists.txt<br>
    llvm/trunk/lib/Transforms/Util<wbr>s/Utils.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/Initia<wbr>lizePasses.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=294351&r1=294350&r2=294351&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/include/llvm/<wbr>InitializePasses.h?rev=294351&<wbr>r1=294350&r2=294351&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/include/llvm/Initia<wbr>lizePasses.h (original)<br>
+++ llvm/trunk/include/llvm/Initia<wbr>lizePasses.h Tue Feb  7 15:10:46 2017<br>
@@ -286,6 +286,7 @@ void initializePostMachineScheduler<wbr>Pass(<br>
 void initializePostOrderFunctionAtt<wbr>rsLegacyPassPass(PassRegistry&<wbr>);<br>
 void initializePostRAHazardRecogniz<wbr>erPass(PassRegistry&);<br>
 void initializePostRASchedulerPass(<wbr>PassRegistry&);<br>
+void initializePredicateInfoPrinter<wbr>LegacyPassPass(PassRegistry &);<br>
 void initializePreISelIntrinsicLowe<wbr>ringLegacyPassPass(PassRegistr<wbr>y&);<br>
 void initializePrintBasicBlockPassP<wbr>ass(PassRegistry&);<br>
 void initializePrintFunctionPassWra<wbr>pperPass(PassRegistry&);<br>
<br>
Added: llvm/trunk/include/llvm/Transf<wbr>orms/Utils/PredicateInfo.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/PredicateInfo.h?rev=294351&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/include/llvm/<wbr>Transforms/Utils/PredicateInfo<wbr>.h?rev=294351&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/include/llvm/Transf<wbr>orms/Utils/PredicateInfo.h (added)<br>
+++ llvm/trunk/include/llvm/Transf<wbr>orms/Utils/PredicateInfo.h Tue Feb  7 15:10:46 2017<br>
@@ -0,0 +1,247 @@<br>
+//===- PredicateInfo.h - Build PredicateInfo ----------------------*-C++-*-<wbr>===//<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>
+// \file<br>
+// \brief<br>
+//<br>
+// This file implements the PredicateInfo analysis, which creates an Extended<br>
+// SSA form for operations used in branch comparisons and llvm.assume<br>
+// comparisons.  Copies of these operations are inserted into the true/false<br>
+// edge (and after assumes), and information attached to the copies.  All uses<br>
+// of the original operation in blocks dominated by the true/false edge (and<br>
+// assume), are replaced with uses of the copies.  This enables passes to easily<br>
+// and sparsely propagate condition based info into the operations that may be<br>
+// affected.<br>
+//<br>
+// Example:<br>
+// %cmp = icmp eq i32 %x, 50<br>
+// br i1 %cmp, label %true, label %false<br>
+// true:<br>
+// ret i32 %x<br>
+// false:<br>
+// ret i32 1<br>
+//<br>
+// will become<br>
+//<br>
+// %cmp = icmp eq i32, %x, 50<br>
+// br i1 %cmp, label %true, label %false<br>
+// true:<br>
+// %x.0 = call @llvm.ssa_copy.i32(i32 %x)<br>
+// ret i32 %x.0<br>
+// false:<br>
+// ret i32 1<br>
+//<br>
+// Using getPredicateInfoFor on x.0 will give you the comparison it is<br>
+// dominated by (the icmp), and that you are located in the true edge of that<br>
+// comparison, which tells you x.0 is 50.<br>
+//<br>
+// In order to reduce the number of copies inserted, predicateinfo is only<br>
+// inserted where it would actually be live.  This means if there are no uses of<br>
+// an operation dominated by the branch edges, or by an assume, the associated<br>
+// predicate info is never inserted.<br>
+//<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#ifndef LLVM_TRANSFORMS_UTILS_PREDICAT<wbr>EINFO_H<br>
+#define LLVM_TRANSFORMS_UTILS_PREDICAT<wbr>EINFO_H<br>
+<br>
+#include "llvm/ADT/DenseMap.h"<br>
+#include "llvm/ADT/SmallPtrSet.h"<br>
+#include "llvm/ADT/SmallVector.h"<br>
+#include "llvm/ADT/ilist.h"<br>
+#include "llvm/ADT/ilist_node.h"<br>
+#include "llvm/ADT/iterator.h"<br>
+#include "llvm/Analysis/AssumptionCache<wbr>.h"<br>
+#include "llvm/IR/BasicBlock.h"<br>
+#include "llvm/IR/Dominators.h"<br>
+#include "llvm/IR/Instructions.h"<br>
+#include "llvm/IR/IntrinsicInst.h"<br>
+#include "llvm/IR/Module.h"<br>
+#include "llvm/IR/OperandTraits.h"<br>
+#include "llvm/IR/Type.h"<br>
+#include "llvm/IR/Use.h"<br>
+#include "llvm/IR/User.h"<br>
+#include "llvm/IR/Value.h"<br>
+#include "llvm/Pass.h"<br>
+#include "llvm/PassAnalysisSupport.h"<br>
+#include "llvm/Support/Casting.h"<br>
+#include "llvm/Support/Compiler.h"<br>
+#include "llvm/Support/ErrorHandling.h"<br>
+#include <algorithm><br>
+#include <cassert><br>
+#include <cstddef><br>
+#include <iterator><br>
+#include <memory><br>
+#include <utility><br>
+<br>
+namespace llvm {<br>
+<br>
+class DominatorTree;<br>
+class Function;<br>
+class Instruction;<br>
+class MemoryAccess;<br>
+class LLVMContext;<br>
+class raw_ostream;<br>
+class OrderedBasicBlock;<br>
+<br>
+enum PredicateType { PT_Branch, PT_Assume };<br>
+<br>
+// Base class for all predicate information we provide.<br>
+// All of our predicate information has at least a comparison.<br>
+class PredicateBase : public ilist_node<PredicateBase> {<br>
+public:<br>
+  PredicateType Type;<br>
+  // The original operand before we renamed it.<br>
+  // This can be use by passes, when destroying predicateinfo, to know<br>
+  // whether they can just drop the intrinsic, or have to merge metadata.<br>
+  Value *OriginalOp;<br>
+  CmpInst *Comparison;<br>
+  PredicateBase(const PredicateBase &) = delete;<br>
+  PredicateBase &operator=(const PredicateBase &) = delete;<br>
+  PredicateBase() = delete;<br></blockquote><div><br></div></div></div><div>This class should have a virtual destructor, since its derived classes are stored in `iplist<PredicateBase> AllInfos;` and, apparently, ilist_node doesn't have a virtual destructor. In its current state the code crashes when compiled with -fsized-deallocation. I'm going to add a virtual destructor.</div><div><div class="h5"><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+protected:<br>
+  PredicateBase(PredicateType PT, Value *Op, CmpInst *Comparison)<br>
+      : Type(PT), OriginalOp(Op), Comparison(Comparison) {}<br>
+};<br>
+<br>
+// Provides predicate information for assumes.  Since assumes are always true,<br>
+// we simply provide the assume instruction, so you can tell your relative<br>
+// position to it.<br>
+class PredicateAssume : public PredicateBase {<br>
+public:<br>
+  IntrinsicInst *AssumeInst;<br>
+  PredicateAssume(Value *Op, IntrinsicInst *AssumeInst, CmpInst *Comparison)<br>
+      : PredicateBase(PT_Assume, Op, Comparison), AssumeInst(AssumeInst) {}<br>
+  PredicateAssume() = delete;<br>
+  static inline bool classof(const PredicateBase *PB) {<br>
+    return PB->Type == PT_Assume;<br>
+  }<br>
+};<br>
+<br>
+// Provides predicate information for branches.<br>
+class PredicateBranch : public PredicateBase {<br>
+public:<br>
+  // This is the block that is conditional upon the comparison.<br>
+  BasicBlock *BranchBB;<br>
+  // This is one of the true/false successors of BranchBB.<br>
+  BasicBlock *SplitBB;<br>
+  // If true, SplitBB is the true successor, otherwise it's the false successor.<br>
+  bool TrueEdge;<br>
+  PredicateBranch(Value *Op, BasicBlock *BranchBB, BasicBlock *SplitBB,<br>
+                  CmpInst *Comparison, bool TakenEdge)<br>
+      : PredicateBase(PT_Branch, Op, Comparison), BranchBB(BranchBB),<br>
+        SplitBB(SplitBB), TrueEdge(TakenEdge) {}<br>
+  PredicateBranch() = delete;<br>
+  static inline bool classof(const PredicateBase *PB) {<br>
+    return PB->Type == PT_Branch;<br>
+  }<br>
+};<br>
+<br>
+// This name is used in a few places, so kick it into their own namespace<br>
+namespace PredicateInfoClasses {<br>
+struct ValueDFS;<br>
+}<br>
+<br>
+/// \brief Encapsulates PredicateInfo, including all data associated with memory<br>
+/// accesses.<br>
+class PredicateInfo {<br>
+private:<br>
+  // Used to store information about each value we might rename.<br>
+  struct ValueInfo {<br>
+    // Information about each possible copy. During processing, this is each<br>
+    // inserted info. After processing, we move the uninserted ones to the<br>
+    // uninserted vector.<br>
+    SmallVector<PredicateBase *, 4> Infos;<br>
+    SmallVector<PredicateBase *, 4> UninsertedInfos;<br>
+  };<br>
+  // This owns the all the predicate infos in the function, placed or not.<br>
+  iplist<PredicateBase> AllInfos;<br>
+<br>
+public:<br>
+  PredicateInfo(Function &, DominatorTree &, AssumptionCache &);<br>
+  ~PredicateInfo();<br>
+<br>
+  void verifyPredicateInfo() const;<br>
+<br>
+  void dump() const;<br>
+  void print(raw_ostream &) const;<br>
+<br>
+  const PredicateBase *getPredicateInfoFor(const Value *V) const {<br>
+    return PredicateMap.lookup(V);<br>
+  }<br>
+<br>
+protected:<br>
+  // Used by PredicateInfo annotater, dumpers, and wrapper pass.<br>
+  friend class PredicateInfoAnnotatedWriter;<br>
+  friend class PredicateInfoPrinterLegacyPass<wbr>;<br>
+<br>
+private:<br>
+  void buildPredicateInfo();<br>
+  void processAssume(IntrinsicInst *, BasicBlock *, SmallPtrSetImpl<Value *> &);<br>
+  void processBranch(BranchInst *, BasicBlock *, SmallPtrSetImpl<Value *> &);<br>
+  void renameUses(SmallPtrSetImpl<Val<wbr>ue *> &);<br>
+  using ValueDFS = PredicateInfoClasses::ValueDFS<wbr>;<br>
+  typedef SmallVectorImpl<ValueDFS> ValueDFSStack;<br>
+  void convertUsesToDFSOrdered(Value *, SmallVectorImpl<ValueDFS> &);<br>
+  Value *materializeStack(unsigned int &, ValueDFSStack &, Value *);<br>
+  bool stackIsInScope(const ValueDFSStack &, int DFSIn, int DFSOut) const;<br>
+  void popStackUntilDFSScope(ValueDFS<wbr>Stack &, int DFSIn, int DFSOut);<br>
+  ValueInfo &getOrCreateValueInfo(Value *);<br>
+  const ValueInfo &getValueInfo(Value *) const;<br>
+  Function &F;<br>
+  DominatorTree &DT;<br>
+  AssumptionCache &AC;<br>
+  // This maps from copy operands to Predicate Info. Note that it does not own<br>
+  // the Predicate Info, they belong to the ValueInfo structs in the ValueInfos<br>
+  // vector.<br>
+  DenseMap<const Value *, const PredicateBase *> PredicateMap;<br>
+  // This stores info about each operand or comparison result we make copies<br>
+  // of.  The real ValueInfos start at index 1, index 0 is unused so that we can<br>
+  // more easily detect invalid indexing.<br>
+  SmallVector<ValueInfo, 32> ValueInfos;<br>
+  // This gives the index into the ValueInfos array for a given Value.  Because<br>
+  // 0 is not a valid Value Info index, you can use DenseMap::lookup and tell<br>
+  // whether it returned a valid result.<br>
+  DenseMap<Value *, unsigned int> ValueInfoNums;<br>
+  // OrderedBasicBlocks used during sorting uses<br>
+  DenseMap<const BasicBlock *, std::unique_ptr<OrderedBasicBl<wbr>ock>> OBBMap;<br>
+};<br>
+<br>
+// This pass does eager building and then printing of PredicateInfo. It is used<br>
+// by<br>
+// the tests to be able to build, dump, and verify PredicateInfo.<br>
+class PredicateInfoPrinterLegacyPass : public FunctionPass {<br>
+public:<br>
+  PredicateInfoPrinterLegacyPass<wbr>();<br>
+<br>
+  static char ID;<br>
+  bool runOnFunction(Function &) override;<br>
+  void getAnalysisUsage(AnalysisUsage &AU) const override;<br>
+};<br>
+<br>
+/// \brief Printer pass for \c PredicateInfo.<br>
+class PredicateInfoPrinterPass<br>
+    : public PassInfoMixin<PredicateInfoPri<wbr>nterPass> {<br>
+  raw_ostream &OS;<br>
+<br>
+public:<br>
+  explicit PredicateInfoPrinterPass(raw_o<wbr>stream &OS) : OS(OS) {}<br>
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);<br>
+};<br>
+<br>
+/// \brief Verifier pass for \c PredicateInfo.<br>
+struct PredicateInfoVerifierPass : PassInfoMixin<PredicateInfoVer<wbr>ifierPass> {<br>
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);<br>
+};<br>
+<br>
+} // end namespace llvm<br>
+<br>
+#endif // LLVM_TRANSFORMS_UTILS_PREDICAT<wbr>EINFO_H<br>
<br>
Modified: llvm/trunk/lib/Passes/PassBuil<wbr>der.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/PassBuilder.cpp?rev=294351&r1=294350&r2=294351&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/lib/Passes/Pa<wbr>ssBuilder.cpp?rev=294351&r1=29<wbr>4350&r2=294351&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Passes/PassBuil<wbr>der.cpp (original)<br>
+++ llvm/trunk/lib/Passes/PassBuil<wbr>der.cpp Tue Feb  7 15:10:46 2017<br>
@@ -136,6 +136,7 @@<br>
 #include "llvm/Transforms/Utils/Mem2Reg<wbr>.h"<br>
 #include "llvm/Transforms/Utils/MemoryS<wbr>SA.h"<br>
 #include "llvm/Transforms/Utils/NameAno<wbr>nGlobals.h"<br>
+#include "llvm/Transforms/Utils/Predica<wbr>teInfo.h"<br>
 #include "llvm/Transforms/Utils/Simplif<wbr>yInstructions.h"<br>
 #include "llvm/Transforms/Utils/SymbolR<wbr>ewriter.h"<br>
 #include "llvm/Transforms/Vectorize/Loo<wbr>pVectorize.h"<br>
<br>
Modified: llvm/trunk/lib/Transforms/Util<wbr>s/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/CMakeLists.txt?rev=294351&r1=294350&r2=294351&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/lib/Transform<wbr>s/Utils/CMakeLists.txt?rev=<wbr>294351&r1=294350&r2=294351&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Transforms/Util<wbr>s/CMakeLists.txt (original)<br>
+++ llvm/trunk/lib/Transforms/Util<wbr>s/CMakeLists.txt Tue Feb  7 15:10:46 2017<br>
@@ -38,6 +38,7 @@ add_llvm_library(LLVMTransform<wbr>Utils<br>
   MetaRenamer.cpp<br>
   ModuleUtils.cpp<br>
   NameAnonGlobals.cpp<br>
+  PredicateInfo.cpp<br>
   PromoteMemoryToRegister.cpp<br>
   StripGCRelocates.cpp<br>
   SSAUpdater.cpp<br>
<br>
Added: llvm/trunk/lib/Transforms/Util<wbr>s/PredicateInfo.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/PredicateInfo.cpp?rev=294351&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/lib/Transform<wbr>s/Utils/PredicateInfo.cpp?rev=<wbr>294351&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Transforms/Util<wbr>s/PredicateInfo.cpp (added)<br>
+++ llvm/trunk/lib/Transforms/Util<wbr>s/PredicateInfo.cpp Tue Feb  7 15:10:46 2017<br>
@@ -0,0 +1,640 @@<br>
+//===-- PredicateInfo.cpp - PredicateInfo Builder--------------------===<wbr>//<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>
+// This file implements the PredicateInfo class.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------===//<br>
+<br>
+#include "llvm/Transforms/Utils/Predica<wbr>teInfo.h"<br>
+#include "llvm/ADT/DenseMap.h"<br>
+#include "llvm/ADT/DepthFirstIterator.h<wbr>"<br>
+#include "llvm/ADT/STLExtras.h"<br>
+#include "llvm/ADT/SmallPtrSet.h"<br>
+#include "llvm/ADT/Statistic.h"<br>
+#include "llvm/Analysis/AssumptionCache<wbr>.h"<br>
+#include "llvm/Analysis/CFG.h"<br>
+#include "llvm/Analysis/OrderedBasicBlo<wbr>ck.h"<br>
+#include "llvm/IR/AssemblyAnnotationWri<wbr>ter.h"<br>
+#include "llvm/IR/DataLayout.h"<br>
+#include "llvm/IR/Dominators.h"<br>
+#include "llvm/IR/GlobalVariable.h"<br>
+#include "llvm/IR/IRBuilder.h"<br>
+#include "llvm/IR/IntrinsicInst.h"<br>
+#include "llvm/IR/LLVMContext.h"<br>
+#include "llvm/IR/Metadata.h"<br>
+#include "llvm/IR/Module.h"<br>
+#include "llvm/IR/PatternMatch.h"<br>
+#include "llvm/Support/Debug.h"<br>
+#include "llvm/Support/FormattedStream.<wbr>h"<br>
+#include "llvm/Transforms/Scalar.h"<br>
+#include <algorithm><br>
+#define DEBUG_TYPE "predicateinfo"<br>
+using namespace llvm;<br>
+using namespace PatternMatch;<br>
+using namespace llvm::PredicateInfoClasses;<br>
+<br>
+INITIALIZE_PASS_BEGIN(Predica<wbr>teInfoPrinterLegacyPass, "print-predicateinfo",<br>
+                      "PredicateInfo Printer", false, false)<br>
+INITIALIZE_PASS_DEPENDENCY(Do<wbr>minatorTreeWrapperPass)<br>
+INITIALIZE_PASS_DEPENDENCY(As<wbr>sumptionCacheTracker)<br>
+INITIALIZE_PASS_END(Predicate<wbr>InfoPrinterLegacyPass, "print-predicateinfo",<br>
+                    "PredicateInfo Printer", false, false)<br>
+static cl::opt<bool> VerifyPredicateInfo(<br>
+    "verify-predicateinfo", cl::init(false), cl::Hidden,<br>
+    cl::desc("Verify PredicateInfo in legacy printer pass."));<br>
+namespace llvm {<br>
+namespace PredicateInfoClasses {<br>
+enum LocalNum {<br>
+  // Operations that must appear first in the block.<br>
+  LN_First,<br>
+  // Operations that are somewhere in the middle of the block, and are sorted on<br>
+  // demand.<br>
+  LN_Middle,<br>
+  // Operations that must appear last in a block, like successor phi node uses.<br>
+  LN_Last<br>
+};<br>
+<br>
+// Associate global and local DFS info with defs and uses, so we can sort them<br>
+// into a global domination ordering.<br>
+struct ValueDFS {<br>
+  int DFSIn = 0;<br>
+  int DFSOut = 0;<br>
+  unsigned int LocalNum = LN_Middle;<br>
+  PredicateBase *PInfo = nullptr;<br>
+  // Only one of Def or Use will be set.<br>
+  Value *Def = nullptr;<br>
+  Use *Use = nullptr;<br>
+};<br>
+<br>
+// This compares ValueDFS structures, creating OrderedBasicBlocks where<br>
+// necessary to compare uses/defs in the same block.  Doing so allows us to walk<br>
+// the minimum number of instructions necessary to compute our def/use ordering.<br>
+struct ValueDFS_Compare {<br>
+  DenseMap<const BasicBlock *, std::unique_ptr<OrderedBasicBl<wbr>ock>> &OBBMap;<br>
+  ValueDFS_Compare(<br>
+      DenseMap<const BasicBlock *, std::unique_ptr<OrderedBasicBl<wbr>ock>> &OBBMap)<br>
+      : OBBMap(OBBMap) {}<br>
+  bool operator()(const ValueDFS &A, const ValueDFS &B) const {<br>
+    if (&A == &B)<br>
+      return false;<br>
+    // The only case we can't directly compare them is when they in the same<br>
+    // block, and both have localnum == middle.  In that case, we have to use<br>
+    // comesbefore to see what the real ordering is, because they are in the<br>
+    // same basic block.<br>
+<br>
+    bool SameBlock = std::tie(A.DFSIn, A.DFSOut) == std::tie(B.DFSIn, B.DFSOut);<br>
+<br>
+    if (!SameBlock || A.LocalNum != LN_Middle || B.LocalNum != LN_Middle)<br>
+      return std::tie(A.DFSIn, A.DFSOut, A.LocalNum, A.Def, A.Use) <<br>
+             std::tie(B.DFSIn, B.DFSOut, B.LocalNum, B.Def, B.Use);<br>
+    return localComesBefore(A, B);<br>
+  }<br>
+<br>
+  // Get the definition of an instruction that occurs in the middle of a block.<br>
+  Value *getMiddleDef(const ValueDFS &VD) const {<br>
+    if (VD.Def)<br>
+      return VD.Def;<br>
+    // It's possible for the defs and uses to be null.  For branches, the local<br>
+    // numbering will say the placed predicaeinfos should go first (IE<br>
+    // LN_beginning), so we won't be in this function. For assumes, we will end<br>
+    // up here, beause we need to order the def we will place relative to the<br>
+    // assume.  So for the purpose of ordering, we pretend the def is the assume<br>
+    // because that is where we will insert the info.<br>
+    if (!VD.Use) {<br>
+      assert(VD.PInfo &&<br>
+             "No def, no use, and no predicateinfo should not occur");<br>
+      assert(isa<PredicateAssume>(VD<wbr>.PInfo) &&<br>
+             "Middle of block should only occur for assumes");<br>
+      return cast<PredicateAssume>(VD.PInfo<wbr>)->AssumeInst;<br>
+    }<br>
+    return nullptr;<br>
+  }<br>
+<br>
+  // Return either the Def, if it's not null, or the user of the Use, if the def<br>
+  // is null.<br>
+  const Instruction *getDefOrUser(const Value *Def, const Use *Use) const {<br>
+    if (Def)<br>
+      return cast<Instruction>(Def);<br>
+    return cast<Instruction>(Use->getUser<wbr>());<br>
+  }<br>
+<br>
+  // This performs the necessary local basic block ordering checks to tell<br>
+  // whether A comes before B, where both are in the same basic block.<br>
+  bool localComesBefore(const ValueDFS &A, const ValueDFS &B) const {<br>
+    auto *ADef = getMiddleDef(A);<br>
+    auto *BDef = getMiddleDef(B);<br>
+<br>
+    // See if we have real values or uses. If we have real values, we are<br>
+    // guaranteed they are instructions or arguments. No matter what, we are<br>
+    // guaranteed they are in the same block if they are instructions.<br>
+    auto *ArgA = dyn_cast_or_null<Argument>(ADe<wbr>f);<br>
+    auto *ArgB = dyn_cast_or_null<Argument>(BDe<wbr>f);<br>
+<br>
+    if (ArgA && !ArgB)<br>
+      return true;<br>
+    if (ArgB && !ArgA)<br>
+      return false;<br>
+    if (ArgA && ArgB)<br>
+      return ArgA->getArgNo() < ArgB->getArgNo();<br>
+<br>
+    auto *AInst = getDefOrUser(ADef, A.Use);<br>
+    auto *BInst = getDefOrUser(BDef, B.Use);<br>
+<br>
+    auto *BB = AInst->getParent();<br>
+    auto LookupResult = OBBMap.find(BB);<br>
+    if (LookupResult != OBBMap.end())<br>
+      return LookupResult->second->dominate<wbr>s(AInst, BInst);<br>
+    else {<br>
+      auto Result = OBBMap.insert({BB, make_unique<OrderedBasicBlock><wbr>(BB)});<br>
+      return Result.first->second->dominate<wbr>s(AInst, BInst);<br>
+    }<br>
+    return std::tie(ADef, A.Use) < std::tie(BDef, B.Use);<br>
+  }<br>
+};<br>
+<br>
+} // namespace PredicateInfoClasses<br>
+<br>
+bool PredicateInfo::stackIsInScope(<wbr>const ValueDFSStack &Stack, int DFSIn,<br>
+                                   int DFSOut) const {<br>
+  if (Stack.empty())<br>
+    return false;<br>
+  return DFSIn >= Stack.back().DFSIn && DFSOut <= Stack.back().DFSOut;<br>
+}<br>
+<br>
+void PredicateInfo::popStackUntilDF<wbr>SScope(ValueDFSStack &Stack, int DFSIn,<br>
+                                          int DFSOut) {<br>
+  while (!Stack.empty() && !stackIsInScope(Stack, DFSIn, DFSOut))<br>
+    Stack.pop_back();<br>
+}<br>
+<br>
+// Convert the uses of Op into a vector of uses, associating global and local<br>
+// DFS info with each one.<br>
+void PredicateInfo::convertUsesToDF<wbr>SOrdered(<br>
+    Value *Op, SmallVectorImpl<ValueDFS> &DFSOrderedSet) {<br>
+  for (auto &U : Op->uses()) {<br>
+    if (auto *I = dyn_cast<Instruction>(U.getUse<wbr>r())) {<br>
+      ValueDFS VD;<br>
+      // Put the phi node uses in the incoming block.<br>
+      BasicBlock *IBlock;<br>
+      if (auto *PN = dyn_cast<PHINode>(I)) {<br>
+        IBlock = PN->getIncomingBlock(U);<br>
+        // Make phi node users appear last in the incoming block<br>
+        // they are from.<br>
+        VD.LocalNum = LN_Last;<br>
+      } else {<br>
+        // If it's not a phi node use, it is somewhere in the middle of the<br>
+        // block.<br>
+        IBlock = I->getParent();<br>
+        VD.LocalNum = LN_Middle;<br>
+      }<br>
+      DomTreeNode *DomNode = DT.getNode(IBlock);<br>
+      // It's possible our use is in an unreachable block. Skip it if so.<br>
+      if (!DomNode)<br>
+        continue;<br>
+      VD.DFSIn = DomNode->getDFSNumIn();<br>
+      VD.DFSOut = DomNode->getDFSNumOut();<br>
+      VD.Use = &U;<br>
+      DFSOrderedSet.push_back(VD);<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+// Collect relevant operations from Comparison that we may want to insert copies<br>
+// for.<br>
+void collectCmpOps(CmpInst *Comparison, SmallVectorImpl<Value *> &CmpOperands) {<br>
+  auto *Op0 = Comparison->getOperand(0);<br>
+  auto *Op1 = Comparison->getOperand(1);<br>
+  if (Op0 == Op1)<br>
+    return;<br>
+  CmpOperands.push_back(Comparis<wbr>on);<br>
+  // Only want real values, not constants.  Additionally, operands with one use<br>
+  // are only being used in the comparison, which means they will not be useful<br>
+  // for us to consider for predicateinfo.<br>
+  //<br>
+  // FIXME: LLVM crashes trying to create an intrinsic declaration of some<br>
+  // pointer to function types that return structs, so we avoid them.<br>
+  if ((isa<Instruction>(Op0) || isa<Argument>(Op0)) && !Op0->hasOneUse() &&<br>
+      !(Op0->getType()->isPointerTy(<wbr>) &&<br>
+        Op0->getType()->getPointerElem<wbr>entType()->isFunctionTy()))<br>
+    CmpOperands.push_back(Op0);<br>
+  if ((isa<Instruction>(Op1) || isa<Argument>(Op1)) && !Op1->hasOneUse() &&<br>
+      !(Op1->getType()->isPointerTy(<wbr>) &&<br>
+        Op1->getType()->getPointerElem<wbr>entType()->isFunctionTy()))<br>
+    CmpOperands.push_back(Op1);<br>
+}<br>
+<br>
+// Process an assume instruction and place relevant operations we want to rename<br>
+// into OpsToRename.<br>
+void PredicateInfo::processAssume(I<wbr>ntrinsicInst *II, BasicBlock *AssumeBB,<br>
+                                  SmallPtrSetImpl<Value *> &OpsToRename) {<br>
+  SmallVector<Value *, 8> CmpOperands;<br>
+  // Second, see if we have a comparison we support<br>
+  SmallVector<Value *, 2> ComparisonsToProcess;<br>
+  CmpInst::Predicate Pred;<br>
+  Value *Operand = II->getOperand(0);<br>
+  if (m_c_And(m_Cmp(Pred, m_Value(), m_Value()),<br>
+              m_Cmp(Pred, m_Value(), m_Value()))<br>
+          .match(II->getOperand(0))) {<br>
+    ComparisonsToProcess.push_back<wbr>(<br>
+        cast<BinaryOperator>(Operand)-<wbr>>getOperand(0));<br>
+    ComparisonsToProcess.push_back<wbr>(<br>
+        cast<BinaryOperator>(Operand)-<wbr>>getOperand(1));<br>
+  } else {<br>
+    ComparisonsToProcess.push_back<wbr>(Operand);<br>
+  }<br>
+  for (auto Comparison : ComparisonsToProcess) {<br>
+    if (auto *Cmp = dyn_cast<CmpInst>(Comparison)) {<br>
+      collectCmpOps(Cmp, CmpOperands);<br>
+      // Now add our copy infos for our operands<br>
+      for (auto *Op : CmpOperands) {<br>
+        OpsToRename.insert(Op);<br>
+        auto &OperandInfo = getOrCreateValueInfo(Op);<br>
+        PredicateBase *PB = new PredicateAssume(Op, II, Cmp);<br>
+        AllInfos.push_back(PB);<br>
+        OperandInfo.Infos.push_back(PB<wbr>);<br>
+      }<br>
+      CmpOperands.clear();<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+// Process a block terminating branch, and place relevant operations to be<br>
+// renamed into OpsToRename.<br>
+void PredicateInfo::processBranch(B<wbr>ranchInst *BI, BasicBlock *BranchBB,<br>
+                                  SmallPtrSetImpl<Value *> &OpsToRename) {<br>
+  SmallVector<Value *, 8> CmpOperands;<br>
+  BasicBlock *FirstBB = BI->getSuccessor(0);<br>
+  BasicBlock *SecondBB = BI->getSuccessor(1);<br>
+  bool FirstSinglePred = FirstBB->getSinglePredecessor(<wbr>);<br>
+  bool SecondSinglePred = SecondBB->getSinglePredecessor<wbr>();<br>
+  SmallVector<BasicBlock *, 2> SuccsToProcess;<br>
+  bool isAnd = false;<br>
+  bool isOr = false;<br>
+  // First make sure we have single preds for these successors, as we can't<br>
+  // usefully propagate true/false info to them if there are multiple paths to<br>
+  // them.<br>
+  if (FirstSinglePred)<br>
+    SuccsToProcess.push_back(First<wbr>BB);<br>
+  if (SecondSinglePred)<br>
+    SuccsToProcess.push_back(Secon<wbr>dBB);<br>
+  if (SuccsToProcess.empty())<br>
+    return;<br>
+  // Second, see if we have a comparison we support<br>
+  SmallVector<Value *, 2> ComparisonsToProcess;<br>
+  CmpInst::Predicate Pred;<br>
+<br>
+  // Match combinations of conditions.<br>
+  if (match(BI->getCondition(), m_And(m_Cmp(Pred, m_Value(), m_Value()),<br>
+                                      m_Cmp(Pred, m_Value(), m_Value()))) ||<br>
+      match(BI->getCondition(), m_Or(m_Cmp(Pred, m_Value(), m_Value()),<br>
+                                     m_Cmp(Pred, m_Value(), m_Value())))) {<br>
+    auto *BinOp = cast<BinaryOperator>(BI->getCo<wbr>ndition());<br>
+    if (BinOp->getOpcode() == Instruction::And)<br>
+      isAnd = true;<br>
+    else if (BinOp->getOpcode() == Instruction::Or)<br>
+      isOr = true;<br>
+    ComparisonsToProcess.push_back<wbr>(BinOp->getOperand(0));<br>
+    ComparisonsToProcess.push_back<wbr>(BinOp->getOperand(1));<br>
+  } else {<br>
+    ComparisonsToProcess.push_back<wbr>(BI->getCondition());<br>
+  }<br>
+  for (auto Comparison : ComparisonsToProcess) {<br>
+    if (auto *Cmp = dyn_cast<CmpInst>(Comparison)) {<br>
+      collectCmpOps(Cmp, CmpOperands);<br>
+      // Now add our copy infos for our operands<br>
+      for (auto *Op : CmpOperands) {<br>
+        OpsToRename.insert(Op);<br>
+        auto &OperandInfo = getOrCreateValueInfo(Op);<br>
+        for (auto *Succ : SuccsToProcess) {<br>
+          bool TakenEdge = (Succ == FirstBB);<br>
+          // For and, only insert on the true edge<br>
+          // For or, only insert on the false edge<br>
+          if ((isAnd && !TakenEdge) || (isOr && TakenEdge))<br>
+            continue;<br>
+          PredicateBase *PB =<br>
+              new PredicateBranch(Op, BranchBB, Succ, Cmp, TakenEdge);<br>
+          AllInfos.push_back(PB);<br>
+          OperandInfo.Infos.push_back(PB<wbr>);<br>
+        }<br>
+      }<br>
+      CmpOperands.clear();<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+// Build predicate info for our function<br>
+void PredicateInfo::buildPredicateI<wbr>nfo() {<br>
+  DT.updateDFSNumbers();<br>
+  // Collect operands to rename from all conditional branch terminators, as well<br>
+  // as assume statements.<br>
+  SmallPtrSet<Value *, 8> OpsToRename;<br>
+  for (auto DTN : depth_first(DT.getRootNode())) {<br>
+    BasicBlock *BranchBB = DTN->getBlock();<br>
+    if (auto *BI = dyn_cast<BranchInst>(BranchBB-<wbr>>getTerminator())) {<br>
+      if (!BI->isConditional())<br>
+        continue;<br>
+      processBranch(BI, BranchBB, OpsToRename);<br>
+    }<br>
+  }<br>
+  for (auto &Assume : AC.assumptions()) {<br>
+    if (auto *II = dyn_cast_or_null<IntrinsicInst<wbr>>(Assume))<br>
+      processAssume(II, II->getParent(), OpsToRename);<br>
+  }<br>
+  // Now rename all our operations.<br>
+  renameUses(OpsToRename);<br>
+}<br>
+Value *PredicateInfo::materializeSta<wbr>ck(unsigned int &Counter,<br>
+                                       ValueDFSStack &RenameStack,<br>
+                                       Value *OrigOp) {<br>
+  // Find the first thing we have to materialize<br>
+  auto RevIter = RenameStack.rbegin();<br>
+  for (; RevIter != RenameStack.rend(); ++RevIter)<br>
+    if (RevIter->Def)<br>
+      break;<br>
+<br>
+  size_t Start = RevIter - RenameStack.rbegin();<br>
+  // The maximum number of things we should be trying to materialize at once<br>
+  // right now is 4, depending on if we had an assume, a branch, and both used<br>
+  // and of conditions.<br>
+  for (auto RenameIter = RenameStack.end() - Start;<br>
+       RenameIter != RenameStack.end(); ++RenameIter) {<br>
+    auto *Op =<br>
+        RenameIter == RenameStack.begin() ? OrigOp : (RenameIter - 1)->Def;<br>
+    ValueDFS &Result = *RenameIter;<br>
+    auto *ValInfo = Result.PInfo;<br>
+    // For branches, we can just place the operand in the split block.  For<br>
+    // assume, we have to place it right before the assume to ensure we dominate<br>
+    // all of our uses.<br>
+    if (isa<PredicateBranch>(ValInfo)<wbr>) {<br>
+      auto *PBranch = cast<PredicateBranch>(ValInfo)<wbr>;<br>
+      // It's possible we are trying to insert multiple predicateinfos in the<br>
+      // same block at the beginning of the block.  When we do this, we need to<br>
+      // insert them one after the other, not one before the other. To see if we<br>
+      // have already inserted predicateinfo into this block, we see if Op !=<br>
+      // OrigOp && Op->getParent() == PBranch->SplitBB.  Op must be an<br>
+      // instruction we inserted if it's not the original op.<br>
+      BasicBlock::iterator InsertPt;<br>
+      if (Op == OrigOp ||<br>
+          cast<Instruction>(Op)->getPare<wbr>nt() != PBranch->SplitBB) {<br>
+        InsertPt = PBranch->SplitBB->begin();<br>
+        // Insert after last phi node.<br>
+        while (isa<PHINode>(InsertPt))<br>
+          ++InsertPt;<br>
+      } else {<br>
+        // Insert after op.<br>
+        InsertPt = ++(cast<Instruction>(Op)->getI<wbr>terator());<br>
+      }<br>
+      IRBuilder<> B(PBranch->SplitBB, InsertPt);<br>
+      Function *IF = Intrinsic::getDeclaration(<br>
+          F.getParent(), Intrinsic::ssa_copy, Op->getType());<br>
+      Value *PIC = B.CreateCall(IF, Op, Op->getName() + "." + Twine(Counter++));<br>
+      PredicateMap.insert({PIC, ValInfo});<br>
+      Result.Def = PIC;<br>
+    } else {<br>
+      auto *PAssume = dyn_cast<PredicateAssume>(ValI<wbr>nfo);<br>
+      assert(PAssume &&<br>
+             "Should not have gotten here without it being an assume");<br>
+      // Unlike above, this should already insert in the right order when we<br>
+      // insert multiple predicateinfos in the same block.  Because we are<br>
+      // always inserting right before the assume (instead of the beginning of a<br>
+      // block), newer insertions will end up after older ones.<br>
+      IRBuilder<> B(PAssume->AssumeInst->getPare<wbr>nt(),<br>
+                    PAssume->AssumeInst->getIterat<wbr>or());<br>
+      Function *IF = Intrinsic::getDeclaration(<br>
+          F.getParent(), Intrinsic::ssa_copy, Op->getType());<br>
+      Value *PIC = B.CreateCall(IF, Op);<br>
+      PredicateMap.insert({PIC, ValInfo});<br>
+      Result.Def = PIC;<br>
+    }<br>
+  }<br>
+  return RenameStack.back().Def;<br>
+}<br>
+<br>
+// Instead of the standard SSA renaming algorithm, which is O(Number of<br>
+// instructions), and walks the entire dominator tree, we walk only the defs +<br>
+// uses.  The standard SSA renaming algorithm does not really rely on the<br>
+// dominator tree except to order the stack push/pops of the renaming stacks, so<br>
+// that defs end up getting pushed before hitting the correct uses.  This does<br>
+// not require the dominator tree, only the *order* of the dominator tree. The<br>
+// complete and correct ordering of the defs and uses, in dominator tree is<br>
+// contained in the DFS numbering of the dominator tree. So we sort the defs and<br>
+// uses into the DFS ordering, and then just use the renaming stack as per<br>
+// normal, pushing when we hit a def (which is a predicateinfo instruction),<br>
+// popping when we are out of the dfs scope for that def, and replacing any uses<br>
+// with top of stack if it exists.  In order to handle liveness without<br>
+// propagating liveness info, we don't actually insert the predicateinfo<br>
+// instruction def until we see a use that it would dominate.  Once we see such<br>
+// a use, we materialize the predicateinfo instruction in the right place and<br>
+// use it.<br>
+//<br>
+// TODO: Use this algorithm to perform fast single-variable renaming in<br>
+// promotememtoreg and memoryssa.<br>
+void PredicateInfo::renameUses(Smal<wbr>lPtrSetImpl<Value *> &OpsToRename) {<br>
+  ValueDFS_Compare Compare(OBBMap);<br>
+  // Compute liveness, and rename in O(uses) per Op.<br>
+  for (auto *Op : OpsToRename) {<br>
+    unsigned Counter = 0;<br>
+    SmallVector<ValueDFS, 16> OrderedUses;<br>
+    const auto &ValueInfo = getValueInfo(Op);<br>
+    // Insert the possible copies into the def/use list.<br>
+    // They will become real copies if we find a real use for them, and never<br>
+    // created otherwise.<br>
+    for (auto &PossibleCopy : ValueInfo.Infos) {<br>
+      ValueDFS VD;<br>
+      BasicBlock *CopyBB = nullptr;<br>
+      // Determine where we are going to place the copy by the copy type.<br>
+      // The predicate info for branches always come first, they will get<br>
+      // materialized in the split block at the top of the block.<br>
+      // The predicate info for assumes will be somewhere in the middle,<br>
+      // it will get materialized in front of the assume.<br>
+      if (const auto *PBranch = dyn_cast<PredicateBranch>(Poss<wbr>ibleCopy)) {<br>
+        CopyBB = PBranch->SplitBB;<br>
+        VD.LocalNum = LN_First;<br>
+      } else if (const auto *PAssume =<br>
+                     dyn_cast<PredicateAssume>(Pos<wbr>sibleCopy)) {<br>
+        CopyBB = PAssume->AssumeInst->getParent<wbr>();<br>
+        VD.LocalNum = LN_Middle;<br>
+      } else<br>
+        llvm_unreachable("Unhandled predicate info type");<br>
+      DomTreeNode *DomNode = DT.getNode(CopyBB);<br>
+      if (!DomNode)<br>
+        continue;<br>
+      VD.DFSIn = DomNode->getDFSNumIn();<br>
+      VD.DFSOut = DomNode->getDFSNumOut();<br>
+      VD.PInfo = PossibleCopy;<br>
+      OrderedUses.push_back(VD);<br>
+    }<br>
+<br>
+    convertUsesToDFSOrdered(Op, OrderedUses);<br>
+    std::sort(OrderedUses.begin(), OrderedUses.end(), Compare);<br>
+    SmallVector<ValueDFS, 8> RenameStack;<br>
+    // For each use, sorted into dfs order, push values and replaces uses with<br>
+    // top of stack, which will represent the reaching def.<br>
+    for (auto &VD : OrderedUses) {<br>
+      // We currently do not materialize copy over copy, but we should decide if<br>
+      // we want to.<br>
+      bool PossibleCopy = VD.PInfo != nullptr;<br>
+      if (RenameStack.empty()) {<br>
+        DEBUG(dbgs() << "Rename Stack is empty\n");<br>
+      } else {<br>
+        DEBUG(dbgs() << "Rename Stack Top DFS numbers are ("<br>
+                     << RenameStack.back().DFSIn << ","<br>
+                     << RenameStack.back().DFSOut << ")\n");<br>
+      }<br>
+<br>
+      DEBUG(dbgs() << "Current DFS numbers are (" << VD.DFSIn << ","<br>
+                   << VD.DFSOut << ")\n");<br>
+<br>
+      bool ShouldPush = (VD.Def || PossibleCopy);<br>
+      bool OutOfScope = !stackIsInScope(RenameStack, VD.DFSIn, VD.DFSOut);<br>
+      if (OutOfScope || ShouldPush) {<br>
+        // Sync to our current scope.<br>
+        popStackUntilDFSScope(RenameSt<wbr>ack, VD.DFSIn, VD.DFSOut);<br>
+        ShouldPush |= (VD.Def || PossibleCopy);<br>
+        if (ShouldPush) {<br>
+          RenameStack.push_back(VD);<br>
+        }<br>
+      }<br>
+      // If we get to this point, and the stack is empty we must have a use<br>
+      // with no renaming needed, just skip it.<br>
+      if (RenameStack.empty())<br>
+        continue;<br>
+      // Skip values, only want to rename the uses<br>
+      if (VD.Def || PossibleCopy)<br>
+        continue;<br>
+      ValueDFS &Result = RenameStack.back();<br>
+<br>
+      // If the possible copy dominates something, materialize our stack up to<br>
+      // this point. This ensures every comparison that affects our operation<br>
+      // ends up with predicateinfo.<br>
+      if (!Result.Def)<br>
+        Result.Def = materializeStack(Counter, RenameStack, Op);<br>
+<br>
+      DEBUG(dbgs() << "Found replacement " << *Result.Def << " for "<br>
+                   << *VD.Use->get() << " in " << *(VD.Use->getUser()) << "\n");<br>
+      assert(DT.dominates(cast<Instr<wbr>uction>(Result.Def), *VD.Use) &&<br>
+             "Predicateinfo def should have dominated this use");<br>
+      VD.Use->set(Result.Def);<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+PredicateInfo::ValueInfo &PredicateInfo::getOrCreateVal<wbr>ueInfo(Value *Operand) {<br>
+  auto OIN = ValueInfoNums.find(Operand);<br>
+  if (OIN == ValueInfoNums.end()) {<br>
+    // This will grow it<br>
+    ValueInfos.resize(ValueInfos.s<wbr>ize() + 1);<br>
+    // This will use the new size and give us a 0 based number of the info<br>
+    auto InsertResult = ValueInfoNums.insert({Operand, ValueInfos.size() - 1});<br>
+    assert(InsertResult.second && "Value info number already existed?");<br>
+    return ValueInfos[InsertResult.first-<wbr>>second];<br>
+  }<br>
+  return ValueInfos[OIN->second];<br>
+}<br>
+<br>
+const PredicateInfo::ValueInfo &<br>
+PredicateInfo::getValueInfo(V<wbr>alue *Operand) const {<br>
+  auto OINI = ValueInfoNums.lookup(Operand);<br>
+  assert(OINI != 0 && "Operand was not really in the Value Info Numbers");<br>
+  assert(OINI < ValueInfos.size() &&<br>
+         "Value Info Number greater than size of Value Info Table");<br>
+  return ValueInfos[OINI];<br>
+}<br>
+<br>
+PredicateInfo::PredicateInfo(<wbr>Function &F, DominatorTree &DT,<br>
+                             AssumptionCache &AC)<br>
+    : F(F), DT(DT), AC(AC) {<br>
+  // Push an empty operand info so that we can detect 0 as not finding one<br>
+  ValueInfos.resize(1);<br>
+  buildPredicateInfo();<br>
+}<br>
+<br>
+PredicateInfo::~PredicateInfo<wbr>() {}<br>
+<br>
+void PredicateInfo::verifyPredicate<wbr>Info() const {}<br>
+<br>
+char PredicateInfoPrinterLegacyPass<wbr>::ID = 0;<br>
+<br>
+PredicateInfoPrinterLegacyPas<wbr>s::PredicateInfoPrinterLegacyP<wbr>ass()<br>
+    : FunctionPass(ID) {<br>
+  initializePredicateInfoPrinter<wbr>LegacyPassPass(<br>
+      *PassRegistry::getPassRegistry<wbr>());<br>
+}<br>
+<br>
+void PredicateInfoPrinterLegacyPass<wbr>::getAnalysisUsage(AnalysisUsa<wbr>ge &AU) const {<br>
+  AU.setPreservesAll();<br>
+  AU.addRequiredTransitive<Domin<wbr>atorTreeWrapperPass>();<br>
+  AU.addRequired<AssumptionCache<wbr>Tracker>();<br>
+}<br>
+<br>
+bool PredicateInfoPrinterLegacyPass<wbr>::runOnFunction(Function &F) {<br>
+  auto &DT = getAnalysis<DominatorTreeWrapp<wbr>erPass>().getDomTree();<br>
+  auto &AC = getAnalysis<AssumptionCacheTra<wbr>cker>().getAssumptionCache(F);<br>
+  auto PredInfo = make_unique<PredicateInfo>(F, DT, AC);<br>
+  PredInfo->print(dbgs());<br>
+  if (VerifyPredicateInfo)<br>
+    PredInfo->verifyPredicateInfo(<wbr>);<br>
+  return false;<br>
+}<br>
+<br>
+PreservedAnalyses PredicateInfoPrinterPass::run(<wbr>Function &F,<br>
+                                                FunctionAnalysisManager &AM) {<br>
+  auto &DT = AM.getResult<DominatorTreeAnal<wbr>ysis>(F);<br>
+  auto &AC = AM.getResult<AssumptionAnalysi<wbr>s>(F);<br>
+  OS << "PredicateInfo for function: " << F.getName() << "\n";<br>
+  make_unique<PredicateInfo>(F, DT, AC)->print(OS);<br>
+<br>
+  return PreservedAnalyses::all();<br>
+}<br>
+<br>
+/// \brief An assembly annotator class to print PredicateInfo information in<br>
+/// comments.<br>
+class PredicateInfoAnnotatedWriter : public AssemblyAnnotationWriter {<br>
+  friend class PredicateInfo;<br>
+  const PredicateInfo *PredInfo;<br>
+<br>
+public:<br>
+  PredicateInfoAnnotatedWriter(c<wbr>onst PredicateInfo *M) : PredInfo(M) {}<br>
+<br>
+  virtual void emitBasicBlockStartAnnot(const BasicBlock *BB,<br>
+                                        formatted_raw_ostream &OS) {}<br>
+<br>
+  virtual void emitInstructionAnnot(const Instruction *I,<br>
+                                    formatted_raw_ostream &OS) {<br>
+    if (const auto *PI = PredInfo->getPredicateInfoFor(<wbr>I)) {<br>
+      OS << "; Has predicate info\n";<br>
+      if (const auto *PB = dyn_cast<PredicateBranch>(PI))<br>
+        OS << "; branch predicate info { TrueEdge: " << PB->TrueEdge<br>
+           << " Comparison:" << *PB->Comparison << " }\n";<br>
+      else if (const auto *PA = dyn_cast<PredicateAssume>(PI))<br>
+        OS << "; assume predicate info {"<br>
+           << " Comparison:" << *PA->Comparison << " }\n";<br>
+    }<br>
+  }<br>
+};<br>
+<br>
+void PredicateInfo::print(raw_ostre<wbr>am &OS) const {<br>
+  PredicateInfoAnnotatedWriter Writer(this);<br>
+  F.print(OS, &Writer);<br>
+}<br>
+<br>
+void PredicateInfo::dump() const {<br>
+  PredicateInfoAnnotatedWriter Writer(this);<br>
+  F.print(dbgs(), &Writer);<br>
+}<br>
+<br>
+PreservedAnalyses PredicateInfoVerifierPass::run<wbr>(Function &F,<br>
+                                                 FunctionAnalysisManager &AM) {<br>
+  auto &DT = AM.getResult<DominatorTreeAnal<wbr>ysis>(F);<br>
+  auto &AC = AM.getResult<AssumptionAnalysi<wbr>s>(F);<br>
+  make_unique<PredicateInfo>(F, DT, AC)->verifyPredicateInfo();<br>
+<br>
+  return PreservedAnalyses::all();<br>
+}<br>
+}<br>
<br>
Modified: llvm/trunk/lib/Transforms/Util<wbr>s/Utils.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/Utils.cpp?rev=294351&r1=294350&r2=294351&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/lib/Transform<wbr>s/Utils/Utils.cpp?rev=294351&<wbr>r1=294350&r2=294351&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Transforms/Util<wbr>s/Utils.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/Util<wbr>s/Utils.cpp Tue Feb  7 15:10:46 2017<br>
@@ -38,6 +38,7 @@ void llvm::initializeTransformUtils<wbr>(Pass<br>
   <wbr>initializeMemorySSAWrapperPass<wbr>Pass(Registry);<br>
   <wbr>initializeMemorySSAPrinterLega<wbr>cyPassPass(Registry);<br>
   <wbr>initializeStripGCRelocatesPass<wbr>(Registry);<br>
+  initializePredicateInfoPrinter<wbr>LegacyPassPass(Registry);<br>
 }<br>
<br>
 /// LLVMInitializeTransformUtils - C binding for initializeTransformUtilsPasses<wbr>.<br>
<br>
Added: llvm/trunk/test/Transforms/Uti<wbr>l/PredicateInfo/condprop.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Util/PredicateInfo/condprop.ll?rev=294351&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/test/Transfor<wbr>ms/Util/PredicateInfo/condprop<wbr>.ll?rev=294351&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/test/Transforms/Uti<wbr>l/PredicateInfo/condprop.ll (added)<br>
+++ llvm/trunk/test/Transforms/Uti<wbr>l/PredicateInfo/condprop.ll Tue Feb  7 15:10:46 2017<br>
@@ -0,0 +1,463 @@<br>
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py<br>
+; RUN: opt -print-predicateinfo -analyze  < %s 2>&1 | FileCheck %s<br>
+<br>
+@a = external global i32               ; <i32*> [#uses=7]<br>
+<br>
+define i32 @test1() nounwind {<br>
+; CHECK-LABEL: @test1(<br>
+; CHECK-NEXT:  entry:<br>
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @a, align 4<br>
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 4<br>
+; CHECK-NEXT:    br i1 [[TMP1]], label [[BB:%.*]], label [[BB1:%.*]]<br>
+; CHECK:       bb:<br>
+; CHECK-NEXT:    br label [[BB8:%.*]]<br>
+; CHECK:       bb1:<br>
+; CHECK-NEXT:    [[TMP2:%.*]] = load i32, i32* @a, align 4<br>
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 5<br>
+; CHECK-NEXT:    br i1 [[TMP3]], label [[BB2:%.*]], label [[BB3:%.*]]<br>
+; CHECK:       bb2:<br>
+; CHECK-NEXT:    br label [[BB8]]<br>
+; CHECK:       bb3:<br>
+; CHECK-NEXT:    [[TMP4:%.*]] = load i32, i32* @a, align 4<br>
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 4<br>
+; CHECK-NEXT:    br i1 [[TMP5]], label [[BB4:%.*]], label [[BB5:%.*]]<br>
+; CHECK:       bb4:<br>
+; CHECK-NEXT:    [[TMP6:%.*]] = load i32, i32* @a, align 4<br>
+; CHECK-NEXT:    [[TMP7:%.*]] = add i32 [[TMP6]], 5<br>
+; CHECK-NEXT:    br label [[BB8]]<br>
+; CHECK:       bb5:<br>
+; CHECK-NEXT:    [[TMP8:%.*]] = load i32, i32* @a, align 4<br>
+; CHECK-NEXT:    [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 5<br>
+; CHECK-NEXT:    br i1 [[TMP9]], label [[BB6:%.*]], label [[BB7:%.*]]<br>
+; CHECK:       bb6:<br>
+; CHECK-NEXT:    [[TMP10:%.*]] = load i32, i32* @a, align 4<br>
+; CHECK-NEXT:    [[TMP11:%.*]] = add i32 [[TMP10]], 4<br>
+; CHECK-NEXT:    br label [[BB8]]<br>
+; CHECK:       bb7:<br>
+; CHECK-NEXT:    [[TMP12:%.*]] = load i32, i32* @a, align 4<br>
+; CHECK-NEXT:    br label [[BB8]]<br>
+; CHECK:       bb8:<br>
+; CHECK-NEXT:    [[DOT0:%.*]] = phi i32 [ [[TMP12]], [[BB7]] ], [ [[TMP11]], [[BB6]] ], [ [[TMP7]], [[BB4]] ], [ 4, [[BB2]] ], [ 5, [[BB]] ]<br>
+; CHECK-NEXT:    br label [[RETURN:%.*]]<br>
+; CHECK:       return:<br>
+; CHECK-NEXT:    ret i32 [[DOT0]]<br>
+;<br>
+entry:<br>
+  %0 = load i32, i32* @a, align 4<br>
+  %1 = icmp eq i32 %0, 4<br>
+  br i1 %1, label %bb, label %bb1<br>
+<br>
+bb:            ; preds = %entry<br>
+  br label %bb8<br>
+<br>
+bb1:           ; preds = %entry<br>
+  %2 = load i32, i32* @a, align 4<br>
+  %3 = icmp eq i32 %2, 5<br>
+  br i1 %3, label %bb2, label %bb3<br>
+<br>
+bb2:           ; preds = %bb1<br>
+  br label %bb8<br>
+<br>
+bb3:           ; preds = %bb1<br>
+  %4 = load i32, i32* @a, align 4<br>
+  %5 = icmp eq i32 %4, 4<br>
+  br i1 %5, label %bb4, label %bb5<br>
+<br>
+bb4:           ; preds = %bb3<br>
+  %6 = load i32, i32* @a, align 4<br>
+  %7 = add i32 %6, 5<br>
+  br label %bb8<br>
+<br>
+bb5:           ; preds = %bb3<br>
+  %8 = load i32, i32* @a, align 4<br>
+  %9 = icmp eq i32 %8, 5<br>
+  br i1 %9, label %bb6, label %bb7<br>
+<br>
+bb6:           ; preds = %bb5<br>
+  %10 = load i32, i32* @a, align 4<br>
+  %11 = add i32 %10, 4<br>
+  br label %bb8<br>
+<br>
+bb7:           ; preds = %bb5<br>
+  %12 = load i32, i32* @a, align 4<br>
+  br label %bb8<br>
+<br>
+bb8:           ; preds = %bb7, %bb6, %bb4, %bb2, %bb<br>
+  %.0 = phi i32 [ %12, %bb7 ], [ %11, %bb6 ], [ %7, %bb4 ], [ 4, %bb2 ], [ 5, %bb ]<br>
+  br label %return<br>
+<br>
+return:                ; preds = %bb8<br>
+  ret i32 %.0<br>
+}<br>
+<br>
+declare void @foo(i1)<br>
+declare void @bar(i32)<br>
+<br>
+define void @test3(i32 %x, i32 %y) {<br>
+; CHECK-LABEL: @test3(<br>
+; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0<br>
+; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0<br>
+; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XZ]], [[YZ]]<br>
+; CHECK-NEXT:    br i1 [[Z]], label [[BOTH_ZERO:%.*]], label [[NOPE:%.*]]<br>
+; CHECK:       both_zero:<br>
+; CHECK:         [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])<br>
+; CHECK:         [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])<br>
+; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])<br>
+; CHECK:         [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[XZ_0]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[YZ_0]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[X_0]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[Y_0]])<br>
+; CHECK-NEXT:    ret void<br>
+; CHECK:       nope:<br>
+; CHECK-NEXT:    call void @foo(i1 [[Z]])<br>
+; CHECK-NEXT:    ret void<br>
+;<br>
+  %xz = icmp eq i32 %x, 0<br>
+  %yz = icmp eq i32 %y, 0<br>
+  %z = and i1 %xz, %yz<br>
+  br i1 %z, label %both_zero, label %nope<br>
+both_zero:<br>
+  call void @foo(i1 %xz)<br>
+  call void @foo(i1 %yz)<br>
+  call void @bar(i32 %x)<br>
+  call void @bar(i32 %y)<br>
+  ret void<br>
+nope:<br>
+  call void @foo(i1 %z)<br>
+  ret void<br>
+}<br>
+<br>
+define void @test4(i1 %b, i32 %x) {<br>
+; CHECK-LABEL: @test4(<br>
+; CHECK-NEXT:    br i1 [[B:%.*]], label [[SW:%.*]], label [[CASE3:%.*]]<br>
+; CHECK:       sw:<br>
+; CHECK-NEXT:    switch i32 [[X:%.*]], label [[DEFAULT:%.*]] [<br>
+; CHECK-NEXT:    i32 0, label [[CASE0:%.*]]<br>
+; CHECK-NEXT:    i32 1, label [[CASE1:%.*]]<br>
+; CHECK-NEXT:    i32 2, label [[CASE0]]<br>
+; CHECK-NEXT:    i32 3, label [[CASE3]]<br>
+; CHECK-NEXT:    i32 4, label [[DEFAULT]]<br>
+; CHECK-NEXT:    ]<br>
+; CHECK:       default:<br>
+; CHECK-NEXT:    call void @bar(i32 [[X]])<br>
+; CHECK-NEXT:    ret void<br>
+; CHECK:       case0:<br>
+; CHECK-NEXT:    call void @bar(i32 [[X]])<br>
+; CHECK-NEXT:    ret void<br>
+; CHECK:       case1:<br>
+; CHECK-NEXT:    call void @bar(i32 [[X]])<br>
+; CHECK-NEXT:    ret void<br>
+; CHECK:       case3:<br>
+; CHECK-NEXT:    call void @bar(i32 [[X]])<br>
+; CHECK-NEXT:    ret void<br>
+;<br>
+  br i1 %b, label %sw, label %case3<br>
+sw:<br>
+  switch i32 %x, label %default [<br>
+  i32 0, label %case0<br>
+  i32 1, label %case1<br>
+  i32 2, label %case0<br>
+  i32 3, label %case3<br>
+  i32 4, label %default<br>
+  ]<br>
+default:<br>
+  call void @bar(i32 %x)<br>
+  ret void<br>
+case0:<br>
+  call void @bar(i32 %x)<br>
+  ret void<br>
+case1:<br>
+  call void @bar(i32 %x)<br>
+  ret void<br>
+case3:<br>
+  call void @bar(i32 %x)<br>
+  ret void<br>
+}<br>
+<br>
+define i1 @test5(i32 %x, i32 %y) {<br>
+; CHECK-LABEL: @test5(<br>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]<br>
+; CHECK-NEXT:    br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]<br>
+; CHECK:       same:<br>
+; CHECK:         [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])<br>
+; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])<br>
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne i32 [[X_0]], [[Y_0]]<br>
+; CHECK-NEXT:    ret i1 [[CMP2]]<br>
+; CHECK:       different:<br>
+; CHECK:         [[Y_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])<br>
+; CHECK:         [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])<br>
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp eq i32 [[X_1]], [[Y_1]]<br>
+; CHECK-NEXT:    ret i1 [[CMP3]]<br>
+;<br>
+  %cmp = icmp eq i32 %x, %y<br>
+  br i1 %cmp, label %same, label %different<br>
+<br>
+same:<br>
+  %cmp2 = icmp ne i32 %x, %y<br>
+  ret i1 %cmp2<br>
+<br>
+different:<br>
+  %cmp3 = icmp eq i32 %x, %y<br>
+  ret i1 %cmp3<br>
+}<br>
+<br>
+define i1 @test6(i32 %x, i32 %y) {<br>
+; CHECK-LABEL: @test6(<br>
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]]<br>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X]], [[Y]]<br>
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp eq i32 [[X]], [[Y]]<br>
+; CHECK-NEXT:    br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]<br>
+; CHECK:       same:<br>
+; CHECK-NEXT:    ret i1 [[CMP2]]<br>
+; CHECK:       different:<br>
+; CHECK-NEXT:    ret i1 [[CMP3]]<br>
+;<br>
+  %cmp2 = icmp ne i32 %x, %y<br>
+  %cmp = icmp eq i32 %x, %y<br>
+  %cmp3 = icmp eq i32 %x, %y<br>
+  br i1 %cmp, label %same, label %different<br>
+<br>
+same:<br>
+  ret i1 %cmp2<br>
+<br>
+different:<br>
+  ret i1 %cmp3<br>
+}<br>
+<br>
+define i1 @test6_fp(float %x, float %y) {<br>
+; CHECK-LABEL: @test6_fp(<br>
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp une float [[X:%.*]], [[Y:%.*]]<br>
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp oeq float [[X]], [[Y]]<br>
+; CHECK-NEXT:    [[CMP3:%.*]] = fcmp oeq float [[X]], [[Y]]<br>
+; CHECK-NEXT:    br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]<br>
+; CHECK:       same:<br>
+; CHECK-NEXT:    ret i1 [[CMP2]]<br>
+; CHECK:       different:<br>
+; CHECK-NEXT:    ret i1 [[CMP3]]<br>
+;<br>
+  %cmp2 = fcmp une float %x, %y<br>
+  %cmp = fcmp oeq float %x, %y<br>
+  %cmp3 = fcmp oeq float  %x, %y<br>
+  br i1 %cmp, label %same, label %different<br>
+<br>
+same:<br>
+  ret i1 %cmp2<br>
+<br>
+different:<br>
+  ret i1 %cmp3<br>
+}<br>
+<br>
+define i1 @test7(i32 %x, i32 %y) {<br>
+; CHECK-LABEL: @test7(<br>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]<br>
+; CHECK-NEXT:    br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]<br>
+; CHECK:       same:<br>
+; CHECK:         [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])<br>
+; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])<br>
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i32 [[X_0]], [[Y_0]]<br>
+; CHECK-NEXT:    ret i1 [[CMP2]]<br>
+; CHECK:       different:<br>
+; CHECK:         [[Y_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])<br>
+; CHECK:         [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])<br>
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp sgt i32 [[X_1]], [[Y_1]]<br>
+; CHECK-NEXT:    ret i1 [[CMP3]]<br>
+;<br>
+  %cmp = icmp sgt i32 %x, %y<br>
+  br i1 %cmp, label %same, label %different<br>
+<br>
+same:<br>
+  %cmp2 = icmp sle i32 %x, %y<br>
+  ret i1 %cmp2<br>
+<br>
+different:<br>
+  %cmp3 = icmp sgt i32 %x, %y<br>
+  ret i1 %cmp3<br>
+}<br>
+<br>
+define i1 @test7_fp(float %x, float %y) {<br>
+; CHECK-LABEL: @test7_fp(<br>
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt float [[X:%.*]], [[Y:%.*]]<br>
+; CHECK-NEXT:    br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]<br>
+; CHECK:       same:<br>
+; CHECK:         [[Y_0:%.*]] = call float @llvm.ssa.copy.f32(float [[Y]])<br>
+; CHECK:         [[X_0:%.*]] = call float @llvm.ssa.copy.f32(float [[X]])<br>
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp ule float [[X_0]], [[Y_0]]<br>
+; CHECK-NEXT:    ret i1 [[CMP2]]<br>
+; CHECK:       different:<br>
+; CHECK:         [[Y_1:%.*]] = call float @llvm.ssa.copy.f32(float [[Y]])<br>
+; CHECK:         [[X_1:%.*]] = call float @llvm.ssa.copy.f32(float [[X]])<br>
+; CHECK-NEXT:    [[CMP3:%.*]] = fcmp ogt float [[X_1]], [[Y_1]]<br>
+; CHECK-NEXT:    ret i1 [[CMP3]]<br>
+;<br>
+  %cmp = fcmp ogt float %x, %y<br>
+  br i1 %cmp, label %same, label %different<br>
+<br>
+same:<br>
+  %cmp2 = fcmp ule float %x, %y<br>
+  ret i1 %cmp2<br>
+<br>
+different:<br>
+  %cmp3 = fcmp ogt float %x, %y<br>
+  ret i1 %cmp3<br>
+}<br>
+<br>
+define i1 @test8(i32 %x, i32 %y) {<br>
+; CHECK-LABEL: @test8(<br>
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sle i32 [[X:%.*]], [[Y:%.*]]<br>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[X]], [[Y]]<br>
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp sgt i32 [[X]], [[Y]]<br>
+; CHECK-NEXT:    br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]<br>
+; CHECK:       same:<br>
+; CHECK-NEXT:    ret i1 [[CMP2]]<br>
+; CHECK:       different:<br>
+; CHECK-NEXT:    ret i1 [[CMP3]]<br>
+;<br>
+  %cmp2 = icmp sle i32 %x, %y<br>
+  %cmp = icmp sgt i32 %x, %y<br>
+  %cmp3 = icmp sgt i32 %x, %y<br>
+  br i1 %cmp, label %same, label %different<br>
+<br>
+same:<br>
+  ret i1 %cmp2<br>
+<br>
+different:<br>
+  ret i1 %cmp3<br>
+}<br>
+<br>
+define i1 @test8_fp(float %x, float %y) {<br>
+; CHECK-LABEL: @test8_fp(<br>
+; CHECK-NEXT:    [[CMP2:%.*]] = fcmp ule float [[X:%.*]], [[Y:%.*]]<br>
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt float [[X]], [[Y]]<br>
+; CHECK-NEXT:    [[CMP3:%.*]] = fcmp ogt float [[X]], [[Y]]<br>
+; CHECK-NEXT:    br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]<br>
+; CHECK:       same:<br>
+; CHECK-NEXT:    ret i1 [[CMP2]]<br>
+; CHECK:       different:<br>
+; CHECK-NEXT:    ret i1 [[CMP3]]<br>
+;<br>
+  %cmp2 = fcmp ule float %x, %y<br>
+  %cmp = fcmp ogt float %x, %y<br>
+  %cmp3 = fcmp ogt float %x, %y<br>
+  br i1 %cmp, label %same, label %different<br>
+<br>
+same:<br>
+  ret i1 %cmp2<br>
+<br>
+different:<br>
+  ret i1 %cmp3<br>
+}<br>
+<br>
+define i32 @test9(i32 %i, i32 %j) {<br>
+; CHECK-LABEL: @test9(<br>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], [[J:%.*]]<br>
+; CHECK-NEXT:    br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[RET:%.*]]<br>
+; CHECK:       cond_true:<br>
+; CHECK:         [[J_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[J]])<br>
+; CHECK:         [[I_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[I]])<br>
+; CHECK-NEXT:    [[DIFF:%.*]] = sub i32 [[I_0]], [[J_0]]<br>
+; CHECK-NEXT:    ret i32 [[DIFF]]<br>
+; CHECK:       ret:<br>
+; CHECK-NEXT:    ret i32 5<br>
+;<br>
+  %cmp = icmp eq i32 %i, %j<br>
+  br i1 %cmp, label %cond_true, label %ret<br>
+<br>
+cond_true:<br>
+  %diff = sub i32 %i, %j<br>
+  ret i32 %diff<br>
+<br>
+ret:<br>
+  ret i32 5<br>
+}<br>
+<br>
+define i32 @test10(i32 %j, i32 %i) {<br>
+; CHECK-LABEL: @test10(<br>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I:%.*]], [[J:%.*]]<br>
+; CHECK-NEXT:    br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[RET:%.*]]<br>
+; CHECK:       cond_true:<br>
+; CHECK:         [[J_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[J]])<br>
+; CHECK:         [[I_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[I]])<br>
+; CHECK-NEXT:    [[DIFF:%.*]] = sub i32 [[I_0]], [[J_0]]<br>
+; CHECK-NEXT:    ret i32 [[DIFF]]<br>
+; CHECK:       ret:<br>
+; CHECK-NEXT:    ret i32 5<br>
+;<br>
+  %cmp = icmp eq i32 %i, %j<br>
+  br i1 %cmp, label %cond_true, label %ret<br>
+<br>
+cond_true:<br>
+  %diff = sub i32 %i, %j<br>
+  ret i32 %diff<br>
+<br>
+ret:<br>
+  ret i32 5<br>
+}<br>
+<br>
+declare i32 @yogibar()<br>
+<br>
+define i32 @test11(i32 %x) {<br>
+; CHECK-LABEL: @test11(<br>
+; CHECK-NEXT:    [[V0:%.*]] = call i32 @yogibar()<br>
+; CHECK-NEXT:    [[V1:%.*]] = call i32 @yogibar()<br>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[V0]], [[V1]]<br>
+; CHECK-NEXT:    br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[NEXT:%.*]]<br>
+; CHECK:       cond_true:<br>
+; CHECK:         [[V1_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V1]])<br>
+; CHECK-NEXT:    ret i32 [[V1_0]]<br>
+; CHECK:       next:<br>
+; CHECK:         [[V0_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V0]])<br>
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[X:%.*]], [[V0_0]]<br>
+; CHECK-NEXT:    br i1 [[CMP2]], label [[COND_TRUE2:%.*]], label [[NEXT2:%.*]]<br>
+; CHECK:       cond_true2:<br>
+; CHECK:         [[V0_0_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V0_0]])<br>
+; CHECK-NEXT:    ret i32 [[V0_0_1]]<br>
+; CHECK:       next2:<br>
+; CHECK-NEXT:    ret i32 0<br>
+;<br>
+  %v0 = call i32 @yogibar()<br>
+  %v1 = call i32 @yogibar()<br>
+  %cmp = icmp eq i32 %v0, %v1<br>
+  br i1 %cmp, label %cond_true, label %next<br>
+<br>
+cond_true:<br>
+  ret i32 %v1<br>
+<br>
+next:<br>
+  %cmp2 = icmp eq i32 %x, %v0<br>
+  br i1 %cmp2, label %cond_true2, label %next2<br>
+<br>
+cond_true2:<br>
+  ret i32 %v0<br>
+<br>
+next2:<br>
+  ret i32 0<br>
+}<br>
+<br>
+define i32 @test12(i32 %x) {<br>
+; CHECK-LABEL: @test12(<br>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0<br>
+; CHECK-NEXT:    br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]<br>
+; CHECK:       cond_true:<br>
+; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])<br>
+; CHECK-NEXT:    br label [[RET:%.*]]<br>
+; CHECK:       cond_false:<br>
+; CHECK:         [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])<br>
+; CHECK-NEXT:    br label [[RET]]<br>
+; CHECK:       ret:<br>
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X_0]], [[COND_TRUE]] ], [ [[X_1]], [[COND_FALSE]] ]<br>
+; CHECK-NEXT:    ret i32 [[RES]]<br>
+;<br>
+  %cmp = icmp eq i32 %x, 0<br>
+  br i1 %cmp, label %cond_true, label %cond_false<br>
+<br>
+cond_true:<br>
+  br label %ret<br>
+<br>
+cond_false:<br>
+  br label %ret<br>
+<br>
+ret:<br>
+  %res = phi i32 [ %x, %cond_true ], [ %x, %cond_false ]<br>
+  ret i32 %res<br>
+}<br>
<br>
Added: llvm/trunk/test/Transforms/Uti<wbr>l/PredicateInfo/testandor.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Util/PredicateInfo/testandor.ll?rev=294351&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/llvm/trunk/test/Transfor<wbr>ms/Util/PredicateInfo/testando<wbr>r.ll?rev=294351&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/test/Transforms/Uti<wbr>l/PredicateInfo/testandor.ll (added)<br>
+++ llvm/trunk/test/Transforms/Uti<wbr>l/PredicateInfo/testandor.ll Tue Feb  7 15:10:46 2017<br>
@@ -0,0 +1,205 @@<br>
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py<br>
+; RUN: opt -print-predicateinfo -analyze < %s 2>&1 | FileCheck %s<br>
+<br>
+declare void @foo(i1)<br>
+declare void @bar(i32)<br>
+declare void @llvm.assume(i1)<br>
+<br>
+define void @testor(i32 %x, i32 %y) {<br>
+; CHECK-LABEL: @testor(<br>
+; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0<br>
+; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0<br>
+; CHECK-NEXT:    [[Z:%.*]] = or i1 [[XZ]], [[YZ]]<br>
+; CHECK-NEXT:    br i1 [[Z]], label [[ONEOF:%.*]], label [[NEITHER:%.*]]<br>
+; CHECK:       oneof:<br>
+; CHECK-NEXT:    call void @foo(i1 [[XZ]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[YZ]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[X]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[Y]])<br>
+; CHECK-NEXT:    ret void<br>
+; CHECK:       neither:<br>
+; CHECK:         [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])<br>
+; CHECK:         [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])<br>
+; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])<br>
+; CHECK:         [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[XZ_0]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[YZ_0]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[X_0]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[Y_0]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[Z]])<br>
+; CHECK-NEXT:    ret void<br>
+;<br>
+  %xz = icmp eq i32 %x, 0<br>
+  %yz = icmp eq i32 %y, 0<br>
+  %z = or i1 %xz, %yz<br>
+  br i1 %z, label %oneof, label %neither<br>
+oneof:<br>
+;; Should not insert on the true edge for or<br>
+  call void @foo(i1 %xz)<br>
+  call void @foo(i1 %yz)<br>
+  call void @bar(i32 %x)<br>
+  call void @bar(i32 %y)<br>
+  ret void<br>
+neither:<br>
+  call void @foo(i1 %xz)<br>
+  call void @foo(i1 %yz)<br>
+  call void @bar(i32 %x)<br>
+  call void @bar(i32 %y)<br>
+  call void @foo(i1 %z)<br>
+  ret void<br>
+}<br>
+define void @testand(i32 %x, i32 %y) {<br>
+; CHECK-LABEL: @testand(<br>
+; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0<br>
+; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0<br>
+; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XZ]], [[YZ]]<br>
+; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]<br>
+; CHECK:       both:<br>
+; CHECK:         [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])<br>
+; CHECK:         [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])<br>
+; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])<br>
+; CHECK:         [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[XZ_0]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[YZ_0]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[X_0]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[Y_0]])<br>
+; CHECK-NEXT:    ret void<br>
+; CHECK:       nope:<br>
+; CHECK-NEXT:    call void @foo(i1 [[XZ]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[YZ]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[X]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[Y]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[Z]])<br>
+; CHECK-NEXT:    ret void<br>
+;<br>
+  %xz = icmp eq i32 %x, 0<br>
+  %yz = icmp eq i32 %y, 0<br>
+  %z = and i1 %xz, %yz<br>
+  br i1 %z, label %both, label %nope<br>
+both:<br>
+  call void @foo(i1 %xz)<br>
+  call void @foo(i1 %yz)<br>
+  call void @bar(i32 %x)<br>
+  call void @bar(i32 %y)<br>
+  ret void<br>
+nope:<br>
+;; Should not insert on the false edge for and<br>
+  call void @foo(i1 %xz)<br>
+  call void @foo(i1 %yz)<br>
+  call void @bar(i32 %x)<br>
+  call void @bar(i32 %y)<br>
+  call void @foo(i1 %z)<br>
+  ret void<br>
+}<br>
+define void @testandsame(i32 %x, i32 %y) {<br>
+; CHECK-LABEL: @testandsame(<br>
+; CHECK-NEXT:    [[XGT:%.*]] = icmp sgt i32 [[X:%.*]], 0<br>
+; CHECK-NEXT:    [[XLT:%.*]] = icmp slt i32 [[X]], 100<br>
+; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XGT]], [[XLT]]<br>
+; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]<br>
+; CHECK:       both:<br>
+; CHECK:         [[XLT_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XLT]])<br>
+; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])<br>
+; CHECK:         [[X_0_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X_0]])<br>
+; CHECK:         [[XGT_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XGT]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[XGT_0]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[XLT_0]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[X_0_1]])<br>
+; CHECK-NEXT:    ret void<br>
+; CHECK:       nope:<br>
+; CHECK-NEXT:    call void @foo(i1 [[XGT]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[XLT]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[Z]])<br>
+; CHECK-NEXT:    ret void<br>
+;<br>
+  %xgt = icmp sgt i32 %x, 0<br>
+  %xlt = icmp slt i32 %x, 100<br>
+  %z = and i1 %xgt, %xlt<br>
+  br i1 %z, label %both, label %nope<br>
+both:<br>
+  call void @foo(i1 %xgt)<br>
+  call void @foo(i1 %xlt)<br>
+  call void @bar(i32 %x)<br>
+  ret void<br>
+nope:<br>
+  call void @foo(i1 %xgt)<br>
+  call void @foo(i1 %xlt)<br>
+  call void @foo(i1 %z)<br>
+  ret void<br>
+}<br>
+<br>
+define void @testandassume(i32 %x, i32 %y) {<br>
+; CHECK-LABEL: @testandassume(<br>
+; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0<br>
+; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0<br>
+; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XZ]], [[YZ]]<br>
+; CHECK:         [[TMP1:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])<br>
+; CHECK:         [[TMP2:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])<br>
+; CHECK:         [[TMP3:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])<br>
+; CHECK:         [[TMP4:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])<br>
+; CHECK-NEXT:    call void @llvm.assume(i1 [[Z]])<br>
+; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]<br>
+; CHECK:       both:<br>
+; CHECK:         [[DOT03:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[TMP4]])<br>
+; CHECK:         [[DOT02:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP3]])<br>
+; CHECK:         [[DOT01:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[TMP2]])<br>
+; CHECK:         [[DOT0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP1]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[DOT0]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[DOT02]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[DOT01]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[DOT03]])<br>
+; CHECK-NEXT:    ret void<br>
+; CHECK:       nope:<br>
+; CHECK-NEXT:    call void @foo(i1 [[Z]])<br>
+; CHECK-NEXT:    ret void<br>
+;<br>
+  %xz = icmp eq i32 %x, 0<br>
+  %yz = icmp eq i32 %y, 0<br>
+  %z = and i1 %xz, %yz<br>
+  call void @llvm.assume(i1 %z)<br>
+  br i1 %z, label %both, label %nope<br>
+both:<br>
+  call void @foo(i1 %xz)<br>
+  call void @foo(i1 %yz)<br>
+  call void @bar(i32 %x)<br>
+  call void @bar(i32 %y)<br>
+  ret void<br>
+nope:<br>
+  call void @foo(i1 %z)<br>
+  ret void<br>
+}<br>
+<br>
+;; Unlike and/or for branches, assume is *always* true, so we only match and for it<br>
+define void @testorassume(i32 %x, i32 %y) {<br>
+;<br>
+; CHECK-LABEL: @testorassume(<br>
+; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0<br>
+; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0<br>
+; CHECK-NEXT:    [[Z:%.*]] = or i1 [[XZ]], [[YZ]]<br>
+; CHECK-NEXT:    call void @llvm.assume(i1 [[Z]])<br>
+; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]<br>
+; CHECK:       both:<br>
+; CHECK-NEXT:    call void @foo(i1 [[XZ]])<br>
+; CHECK-NEXT:    call void @foo(i1 [[YZ]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[X]])<br>
+; CHECK-NEXT:    call void @bar(i32 [[Y]])<br>
+; CHECK-NEXT:    ret void<br>
+; CHECK:       nope:<br>
+; CHECK-NEXT:    call void @foo(i1 [[Z]])<br>
+; CHECK-NEXT:    ret void<br>
+;<br>
+  %xz = icmp eq i32 %x, 0<br>
+  %yz = icmp eq i32 %y, 0<br>
+  %z = or i1 %xz, %yz<br>
+  call void @llvm.assume(i1 %z)<br>
+  br i1 %z, label %both, label %nope<br>
+both:<br>
+  call void @foo(i1 %xz)<br>
+  call void @foo(i1 %yz)<br>
+  call void @bar(i32 %x)<br>
+  call void @bar(i32 %y)<br>
+  ret void<br>
+nope:<br>
+  call void @foo(i1 %z)<br>
+  ret void<br>
+}<br>
<br>
<br>
______________________________<wbr>_________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-commits</a><br>
</blockquote></div></div></div><br></div></div>
</blockquote></div><br></div>