<div dir="ltr">Thanks for the information. I'm looking into this.<br><div><br></div><div>-Rong</div></div><br><div class="gmail_quote"><div dir="ltr">On Tue, Nov 13, 2018 at 10:12 PM Maxim Kazantsev <<a href="mailto:max.kazantsev@azul.com">max.kazantsev@azul.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello Rong,<br>
<br>
It seems that this patch contains a bug that causes a miscompile on our test. I have filed a bug <a href="https://bugs.llvm.org/show_bug.cgi?id=39658" rel="noreferrer" target="_blank">https://bugs.llvm.org/show_bug.cgi?id=39658</a> with description of the failure. We know for sure that disabling of this pass makes the failure gone, but I wasn't able to figure out what exactly is wrong about the transforms it does.<br>
<br>
You can find the IR on which we see the transform triggering and the machine function before and after this particular transform in bug attachment.<br>
<br>
Please take a look at this bug and fix or disable this transform until we can figure out the fix. I'll gladly provide you any extra information you need.<br>
<br>
Thanks,<br>
Max<br>
<br>
-----Original Message-----<br>
From: llvm-commits <<a href="mailto:llvm-commits-bounces@lists.llvm.org" target="_blank">llvm-commits-bounces@lists.llvm.org</a>> On Behalf Of Rong Xu via llvm-commits<br>
Sent: Wednesday, October 10, 2018 5:04 AM<br>
To: <a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
Subject: [llvm] r344085 - Recommit r343993: [X86] condition branches folding for three-way conditional codes<br>
<br>
Author: xur<br>
Date: Tue Oct  9 15:03:40 2018<br>
New Revision: 344085<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=344085&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=344085&view=rev</a><br>
Log:<br>
Recommit r343993: [X86] condition branches folding for three-way conditional codes<br>
<br>
Fix the memory issue exposed by sanitizer.<br>
<br>
Added:<br>
    llvm/trunk/lib/Target/X86/X86CondBrFolding.cpp<br>
    llvm/trunk/test/CodeGen/X86/condbr_if.ll<br>
    llvm/trunk/test/CodeGen/X86/condbr_switch.ll<br>
Modified:<br>
    llvm/trunk/lib/Target/X86/CMakeLists.txt<br>
    llvm/trunk/lib/Target/X86/X86.h<br>
    llvm/trunk/lib/Target/X86/X86.td<br>
    llvm/trunk/lib/Target/X86/X86Subtarget.h<br>
    llvm/trunk/lib/Target/X86/X86TargetMachine.cpp<br>
    llvm/trunk/test/CodeGen/X86/O3-pipeline.ll<br>
<br>
Modified: llvm/trunk/lib/Target/X86/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/CMakeLists.txt?rev=344085&r1=344084&r2=344085&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/CMakeLists.txt?rev=344085&r1=344084&r2=344085&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/X86/CMakeLists.txt (original)<br>
+++ llvm/trunk/lib/Target/X86/CMakeLists.txt Tue Oct  9 15:03:40 2018<br>
@@ -27,6 +27,7 @@ set(sources<br>
   X86CallingConv.cpp<br>
   X86CallLowering.cpp<br>
   X86CmovConversion.cpp<br>
+  X86CondBrFolding.cpp<br>
   X86DomainReassignment.cpp<br>
   X86ExpandPseudo.cpp<br>
   X86FastISel.cpp<br>
<br>
Modified: llvm/trunk/lib/Target/X86/X86.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86.h?rev=344085&r1=344084&r2=344085&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86.h?rev=344085&r1=344084&r2=344085&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/X86/X86.h (original)<br>
+++ llvm/trunk/lib/Target/X86/X86.h Tue Oct  9 15:03:40 2018<br>
@@ -75,6 +75,9 @@ FunctionPass *createX86OptimizeLEAs();  /// Return a pass that transforms setcc + movzx pairs into xor + setcc.<br>
 FunctionPass *createX86FixupSetCC();<br>
<br>
+/// Return a pass that folds conditional branch jumps.<br>
+FunctionPass *createX86CondBrFolding();<br>
+<br>
 /// Return a pass that avoids creating store forward block issues in the hardware.<br>
 FunctionPass *createX86AvoidStoreForwardingBlocks();<br>
<br>
<br>
Modified: llvm/trunk/lib/Target/X86/X86.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86.td?rev=344085&r1=344084&r2=344085&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86.td?rev=344085&r1=344084&r2=344085&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/X86/X86.td (original)<br>
+++ llvm/trunk/lib/Target/X86/X86.td Tue Oct  9 15:03:40 2018<br>
@@ -404,6 +404,12 @@ def FeatureFastBEXTR : SubtargetFeature<<br>
           "Indicates that the BEXTR instruction is implemented as a single uop "<br>
           "with good throughput.">;<br>
<br>
+// Merge branches using three-way conditional code.<br>
+def FeatureMergeToThreeWayBranch : SubtargetFeature<"merge-to-threeway-branch",<br>
+                                        "ThreewayBranchProfitable", "true",<br>
+                                        "Merge branches to a three-way "<br>
+                                        "conditional branch">;<br>
+<br>
 //===----------------------------------------------------------------------===//<br>
 // Register File Description<br>
 //===----------------------------------------------------------------------===//<br>
@@ -732,6 +738,7 @@ def SNBFeatures : ProcessorFeatures<[],<br>
   FeatureFastScalarFSQRT,<br>
   FeatureFastSHLDRotate,<br>
   FeatureSlowIncDec,<br>
+  FeatureMergeToThreeWayBranch,<br>
   FeatureMacroFusion<br>
 ]>;<br>
<br>
<br>
Added: llvm/trunk/lib/Target/X86/X86CondBrFolding.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86CondBrFolding.cpp?rev=344085&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86CondBrFolding.cpp?rev=344085&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/X86/X86CondBrFolding.cpp (added)<br>
+++ llvm/trunk/lib/Target/X86/X86CondBrFolding.cpp Tue Oct  9 15:03:40 <br>
+++ 2018<br>
@@ -0,0 +1,579 @@<br>
+//===---- X86CondBrFolding.cpp - optimize conditional branches <br>
+------------===// //<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open <br>
+Source // License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------------------------------------------------<br>
+----===// // This file defines a pass that optimizes condition branches <br>
+on x86 by taking // advantage of the three-way conditional code <br>
+generated by compare // instructions.<br>
+// Currently, it tries to hoisting EQ and NE conditional branch to a <br>
+dominant // conditional branch condition where the same EQ/NE <br>
+conditional code is // computed. An example:<br>
+//   bb_0:<br>
+//     cmp %0, 19<br>
+//     jg bb_1<br>
+//     jmp bb_2<br>
+//   bb_1:<br>
+//     cmp %0, 40<br>
+//     jg bb_3<br>
+//     jmp bb_4<br>
+//   bb_4:<br>
+//     cmp %0, 20<br>
+//     je bb_5<br>
+//     jmp bb_6<br>
+// Here we could combine the two compares in bb_0 and bb_4 and have the <br>
+// following code:<br>
+//   bb_0:<br>
+//     cmp %0, 20<br>
+//     jg bb_1<br>
+//     jl bb_2<br>
+//     jmp bb_5<br>
+//   bb_1:<br>
+//     cmp %0, 40<br>
+//     jg bb_3<br>
+//     jmp bb_6<br>
+// For the case of %0 == 20 (bb_5), we eliminate two jumps, and the <br>
+control // height for bb_6 is also reduced. bb_4 is gone after the optimization.<br>
+//<br>
+// There are plenty of this code patterns, especially from the switch <br>
+case // lowing where we generate compare of "pivot-1" for the inner <br>
+nodes in the // binary search tree.<br>
+//===------------------------------------------------------------------<br>
+----===//<br>
+<br>
+#include "X86.h"<br>
+#include "X86InstrInfo.h"<br>
+#include "X86Subtarget.h"<br>
+#include "llvm/ADT/Statistic.h"<br>
+#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"<br>
+#include "llvm/CodeGen/MachineFunctionPass.h"<br>
+#include "llvm/CodeGen/MachineInstrBuilder.h"<br>
+#include "llvm/CodeGen/MachineRegisterInfo.h"<br>
+#include "llvm/Support/BranchProbability.h"<br>
+<br>
+using namespace llvm;<br>
+<br>
+#define DEBUG_TYPE "x86-condbr-folding"<br>
+<br>
+STATISTIC(NumFixedCondBrs, "Number of x86 condbr folded");<br>
+<br>
+namespace {<br>
+class X86CondBrFoldingPass : public MachineFunctionPass {<br>
+public:<br>
+  X86CondBrFoldingPass() : MachineFunctionPass(ID) {}<br>
+<br>
+  StringRef getPassName() const override { return "X86 CondBr Folding"; <br>
+ }<br>
+<br>
+  bool runOnMachineFunction(MachineFunction &MF) override;<br>
+<br>
+  void getAnalysisUsage(AnalysisUsage &AU) const override {<br>
+    MachineFunctionPass::getAnalysisUsage(AU);<br>
+    AU.addRequired<MachineBranchProbabilityInfo>();<br>
+  }<br>
+<br>
+private:<br>
+  static char ID;<br>
+};<br>
+<br>
+char X86CondBrFoldingPass::ID = 0;<br>
+} // namespace<br>
+<br>
+FunctionPass *llvm::createX86CondBrFolding() {<br>
+  return new X86CondBrFoldingPass();<br>
+}<br>
+<br>
+// A class the stores the auxiliary information for each MBB.<br>
+struct TargetMBBInfo {<br>
+  MachineBasicBlock *TBB;<br>
+  MachineBasicBlock *FBB;<br>
+  MachineInstr *BrInstr;<br>
+  MachineInstr *CmpInstr;<br>
+  X86::CondCode BranchCode;<br>
+  unsigned SrcReg;<br>
+  int CmpValue;<br>
+  bool Modified;<br>
+  bool CmpBrOnly;<br>
+};<br>
+<br>
+// A class that optimizes the conditional branch by hoisting and merge CondCode.<br>
+class X86CondBrFolding {<br>
+public:<br>
+  X86CondBrFolding(const X86InstrInfo *TII,<br>
+                   const MachineBranchProbabilityInfo *MBPI,<br>
+                   MachineFunction &MF)<br>
+      : TII(TII), MBPI(MBPI), MF(MF) {}<br>
+  bool optimize();<br>
+<br>
+private:<br>
+  const X86InstrInfo *TII;<br>
+  const MachineBranchProbabilityInfo *MBPI;<br>
+  MachineFunction &MF;<br>
+  std::vector<std::unique_ptr<TargetMBBInfo>> MBBInfos;<br>
+  SmallVector<MachineBasicBlock *, 4> RemoveList;<br>
+<br>
+  void optimizeCondBr(MachineBasicBlock &MBB,<br>
+                      SmallVectorImpl<MachineBasicBlock *> <br>
+&BranchPath);<br>
+  void fixBranchProb(MachineBasicBlock *NextMBB, MachineBasicBlock *RootMBB,<br>
+                     SmallVectorImpl<MachineBasicBlock *> &BranchPath);<br>
+  void replaceBrDest(MachineBasicBlock *MBB, MachineBasicBlock *OrigDest,<br>
+                     MachineBasicBlock *NewDest);<br>
+  void fixupModifiedCond(MachineBasicBlock *MBB);<br>
+  std::unique_ptr<TargetMBBInfo> analyzeMBB(MachineBasicBlock &MBB);<br>
+  static bool analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,<br>
+                             int &CmpValue);<br>
+  bool findPath(MachineBasicBlock *MBB,<br>
+                SmallVectorImpl<MachineBasicBlock *> &BranchPath);<br>
+  TargetMBBInfo *getMBBInfo(MachineBasicBlock *MBB) const {<br>
+    return MBBInfos[MBB->getNumber()].get();<br>
+  }<br>
+};<br>
+<br>
+// Find a valid path that we can reuse the CondCode.<br>
+// The resulted path (if return true) is stored in BranchPath.<br>
+// Return value:<br>
+//  false: is no valid path is found.<br>
+//  true: a valid path is found and the targetBB can be reached.<br>
+bool X86CondBrFolding::findPath(<br>
+    MachineBasicBlock *MBB, SmallVectorImpl<MachineBasicBlock *> <br>
+&BranchPath) {<br>
+  TargetMBBInfo *MBBInfo = getMBBInfo(MBB);<br>
+  assert(MBBInfo && "Expecting a candidate MBB");<br>
+  int CmpValue = MBBInfo->CmpValue;<br>
+<br>
+  MachineBasicBlock *PredMBB = *MBB->pred_begin();  MachineBasicBlock <br>
+ *SaveMBB = MBB;  while (PredMBB) {<br>
+    TargetMBBInfo *PredMBBInfo = getMBBInfo(PredMBB);<br>
+    if (!PredMBBInfo || PredMBBInfo->SrcReg != MBBInfo->SrcReg)<br>
+      return false;<br>
+<br>
+    assert(SaveMBB == PredMBBInfo->TBB || SaveMBB == PredMBBInfo->FBB);<br>
+    bool IsFalseBranch = (SaveMBB == PredMBBInfo->FBB);<br>
+<br>
+    X86::CondCode CC = PredMBBInfo->BranchCode;<br>
+    assert(CC == X86::COND_L || CC == X86::COND_G || CC == X86::COND_E);<br>
+    int PredCmpValue = PredMBBInfo->CmpValue;<br>
+    bool ValueCmpTrue = ((CmpValue < PredCmpValue && CC == X86::COND_L) ||<br>
+                         (CmpValue > PredCmpValue && CC == X86::COND_G) ||<br>
+                         (CmpValue == PredCmpValue && CC == X86::COND_E));<br>
+    // Check if both the result of value compare and the branch target match.<br>
+    if (!(ValueCmpTrue ^ IsFalseBranch)) {<br>
+      LLVM_DEBUG(dbgs() << "Dead BB detected!\n");<br>
+      return false;<br>
+    }<br>
+<br>
+    BranchPath.push_back(PredMBB);<br>
+    // These are the conditions on which we could combine the compares.<br>
+    if ((CmpValue == PredCmpValue) ||<br>
+        (CmpValue == PredCmpValue - 1 && CC == X86::COND_L) ||<br>
+        (CmpValue == PredCmpValue + 1 && CC == X86::COND_G))<br>
+      return true;<br>
+<br>
+    // If PredMBB has more than on preds, or not a pure cmp and br, we bailout.<br>
+    if (PredMBB->pred_size() != 1 || !PredMBBInfo->CmpBrOnly)<br>
+      return false;<br>
+<br>
+    SaveMBB = PredMBB;<br>
+    PredMBB = *PredMBB->pred_begin();<br>
+  }<br>
+  return false;<br>
+}<br>
+<br>
+// Fix up any PHI node in the successor of MBB.<br>
+static void fixPHIsInSucc(MachineBasicBlock *MBB, MachineBasicBlock *OldMBB,<br>
+                          MachineBasicBlock *NewMBB) {<br>
+  if (NewMBB == OldMBB)<br>
+    return;<br>
+  for (auto MI = MBB->instr_begin(), ME = MBB->instr_end();<br>
+       MI != ME && MI->isPHI(); ++MI)<br>
+    for (unsigned i = 2, e = MI->getNumOperands() + 1; i != e; i += 2) {<br>
+      MachineOperand &MO = MI->getOperand(i);<br>
+      if (MO.getMBB() == OldMBB)<br>
+        MO.setMBB(NewMBB);<br>
+    }<br>
+}<br>
+<br>
+// Utility function to set branch probability for edge MBB->SuccMBB.<br>
+static inline bool setBranchProb(MachineBasicBlock *MBB,<br>
+                                 MachineBasicBlock *SuccMBB,<br>
+                                 BranchProbability Prob) {<br>
+  auto MBBI = std::find(MBB->succ_begin(), MBB->succ_end(), SuccMBB);<br>
+  if (MBBI == MBB->succ_end())<br>
+    return false;<br>
+  MBB->setSuccProbability(MBBI, Prob);<br>
+  return true;<br>
+}<br>
+<br>
+// Utility function to find the unconditional br instruction in MBB.<br>
+static inline MachineBasicBlock::iterator <br>
+findUncondBrI(MachineBasicBlock *MBB) {<br>
+  return std::find_if(MBB->begin(), MBB->end(), [](MachineInstr &MI) -> bool {<br>
+    return MI.getOpcode() == X86::JMP_1;<br>
+  });<br>
+}<br>
+<br>
+// Replace MBB's original successor, OrigDest, with NewDest.<br>
+// Also update the MBBInfo for MBB.<br>
+void X86CondBrFolding::replaceBrDest(MachineBasicBlock *MBB,<br>
+                                     MachineBasicBlock *OrigDest,<br>
+                                     MachineBasicBlock *NewDest) {<br>
+  TargetMBBInfo *MBBInfo = getMBBInfo(MBB);<br>
+  MachineInstr *BrMI;<br>
+  if (MBBInfo->TBB == OrigDest) {<br>
+    BrMI = MBBInfo->BrInstr;<br>
+    unsigned JNCC = GetCondBranchFromCond(MBBInfo->BranchCode);<br>
+    MachineInstrBuilder MIB =<br>
+        BuildMI(*MBB, BrMI, MBB->findDebugLoc(BrMI), TII->get(JNCC))<br>
+            .addMBB(NewDest);<br>
+    MBBInfo->TBB = NewDest;<br>
+    MBBInfo->BrInstr = MIB.getInstr();<br>
+  } else { // Should be the unconditional jump stmt.<br>
+    MachineBasicBlock::iterator UncondBrI = findUncondBrI(MBB);<br>
+    BuildMI(*MBB, UncondBrI, MBB->findDebugLoc(UncondBrI), TII->get(X86::JMP_1))<br>
+        .addMBB(NewDest);<br>
+    MBBInfo->FBB = NewDest;<br>
+    BrMI = &*UncondBrI;<br>
+  }<br>
+  fixPHIsInSucc(NewDest, OrigDest, MBB);<br>
+  BrMI->eraseFromParent();<br>
+  MBB->addSuccessor(NewDest);<br>
+  setBranchProb(MBB, NewDest, MBPI->getEdgeProbability(MBB, OrigDest));<br>
+  MBB->removeSuccessor(OrigDest);<br>
+}<br>
+<br>
+// Change the CondCode and BrInstr according to MBBInfo.<br>
+void X86CondBrFolding::fixupModifiedCond(MachineBasicBlock *MBB) {<br>
+  TargetMBBInfo *MBBInfo = getMBBInfo(MBB);<br>
+  if (!MBBInfo->Modified)<br>
+    return;<br>
+<br>
+  MachineInstr *BrMI = MBBInfo->BrInstr;  X86::CondCode CC = <br>
+ MBBInfo->BranchCode;  MachineInstrBuilder MIB = BuildMI(*MBB, BrMI, <br>
+ MBB->findDebugLoc(BrMI),<br>
+                                    TII->get(GetCondBranchFromCond(CC)))<br>
+                                .addMBB(MBBInfo->TBB);  <br>
+ BrMI->eraseFromParent();  MBBInfo->BrInstr = MIB.getInstr();<br>
+<br>
+  MachineBasicBlock::iterator UncondBrI = findUncondBrI(MBB);<br>
+  BuildMI(*MBB, UncondBrI, MBB->findDebugLoc(UncondBrI), TII->get(X86::JMP_1))<br>
+      .addMBB(MBBInfo->FBB);<br>
+  MBB->erase(UncondBrI);<br>
+  MBBInfo->Modified = false;<br>
+}<br>
+<br>
+//<br>
+// Apply the transformation:<br>
+//  RootMBB -1-> ... PredMBB -3-> MBB -5-> TargetMBB<br>
+//     \-2->           \-4->       \-6-> FalseMBB<br>
+// ==><br>
+//             RootMBB -1-> ... PredMBB -7-> FalseMBB<br>
+// TargetMBB <-8-/ \-2->           \-4-><br>
+//<br>
+// Note that PredMBB and RootMBB could be the same.<br>
+// And in the case of dead TargetMBB, we will not have TargetMBB and edge 8.<br>
+//<br>
+// There are some special handling where the RootMBB is COND_E in which <br>
+case // we directly short-cycle the brinstr.<br>
+//<br>
+void X86CondBrFolding::optimizeCondBr(<br>
+    MachineBasicBlock &MBB, SmallVectorImpl<MachineBasicBlock *> <br>
+&BranchPath) {<br>
+<br>
+  X86::CondCode CC;<br>
+  TargetMBBInfo *MBBInfo = getMBBInfo(&MBB);  assert(MBBInfo && <br>
+ "Expecting a candidate MBB");  MachineBasicBlock *TargetMBB = <br>
+ MBBInfo->TBB;  BranchProbability TargetProb = <br>
+ MBPI->getEdgeProbability(&MBB, MBBInfo->TBB);<br>
+<br>
+  // Forward the jump from MBB's predecessor to MBB's false target.<br>
+  MachineBasicBlock *PredMBB = BranchPath.front();  TargetMBBInfo <br>
+ *PredMBBInfo = getMBBInfo(PredMBB);  assert(PredMBBInfo && "Expecting <br>
+ a candidate MBB");  if (PredMBBInfo->Modified)<br>
+    fixupModifiedCond(PredMBB);<br>
+  CC = PredMBBInfo->BranchCode;<br>
+  // Don't do this if depth of BranchPath is 1 and PredMBB is of COND_E.<br>
+  // We will short-cycle directly for this case.<br>
+  if (!(CC == X86::COND_E && BranchPath.size() == 1))<br>
+    replaceBrDest(PredMBB, &MBB, MBBInfo->FBB);<br>
+<br>
+  MachineBasicBlock *RootMBB = BranchPath.back();  TargetMBBInfo <br>
+ *RootMBBInfo = getMBBInfo(RootMBB);  assert(RootMBBInfo && "Expecting <br>
+ a candidate MBB");  if (RootMBBInfo->Modified)<br>
+    fixupModifiedCond(RootMBB);<br>
+  CC = RootMBBInfo->BranchCode;<br>
+<br>
+  if (CC != X86::COND_E) {<br>
+    MachineBasicBlock::iterator UncondBrI = findUncondBrI(RootMBB);<br>
+    // RootMBB: Cond jump to the original not-taken MBB.<br>
+    X86::CondCode NewCC;<br>
+    switch (CC) {<br>
+    case X86::COND_L:<br>
+      NewCC = X86::COND_G;<br>
+      break;<br>
+    case X86::COND_G:<br>
+      NewCC = X86::COND_L;<br>
+      break;<br>
+    default:<br>
+      llvm_unreachable("unexpected condtional code.");<br>
+    }<br>
+    BuildMI(*RootMBB, UncondBrI, RootMBB->findDebugLoc(UncondBrI),<br>
+            TII->get(GetCondBranchFromCond(NewCC)))<br>
+        .addMBB(RootMBBInfo->FBB);<br>
+<br>
+    // RootMBB: Jump to TargetMBB<br>
+    BuildMI(*RootMBB, UncondBrI, RootMBB->findDebugLoc(UncondBrI),<br>
+            TII->get(X86::JMP_1))<br>
+        .addMBB(TargetMBB);<br>
+    RootMBB->addSuccessor(TargetMBB);<br>
+    fixPHIsInSucc(TargetMBB, &MBB, RootMBB);<br>
+    RootMBB->erase(UncondBrI);<br>
+  } else {<br>
+    replaceBrDest(RootMBB, RootMBBInfo->TBB, TargetMBB);  }<br>
+<br>
+  // Fix RootMBB's CmpValue to MBB's CmpValue to TargetMBB. Don't set <br>
+ Imm  // directly. Move MBB's stmt to here as the opcode might be different.<br>
+  if (RootMBBInfo->CmpValue != MBBInfo->CmpValue) {<br>
+    MachineInstr *NewCmp = MBBInfo->CmpInstr;<br>
+    NewCmp->removeFromParent();<br>
+    RootMBB->insert(RootMBBInfo->CmpInstr, NewCmp);<br>
+    RootMBBInfo->CmpInstr->eraseFromParent();<br>
+  }<br>
+<br>
+  // Fix branch Probabilities.<br>
+  auto fixBranchProb = [&](MachineBasicBlock *NextMBB) {<br>
+    BranchProbability Prob;<br>
+    for (auto &I : BranchPath) {<br>
+      MachineBasicBlock *ThisMBB = I;<br>
+      if (!ThisMBB->hasSuccessorProbabilities() ||<br>
+          !ThisMBB->isSuccessor(NextMBB))<br>
+        break;<br>
+      Prob = MBPI->getEdgeProbability(ThisMBB, NextMBB);<br>
+      if (Prob.isUnknown())<br>
+        break;<br>
+      TargetProb = Prob * TargetProb;<br>
+      Prob = Prob - TargetProb;<br>
+      setBranchProb(ThisMBB, NextMBB, Prob);<br>
+      if (ThisMBB == RootMBB) {<br>
+        setBranchProb(ThisMBB, TargetMBB, TargetProb);<br>
+      }<br>
+      ThisMBB->normalizeSuccProbs();<br>
+      if (ThisMBB == RootMBB)<br>
+        break;<br>
+      NextMBB = ThisMBB;<br>
+    }<br>
+    return true;<br>
+  };<br>
+  if (CC != X86::COND_E && !TargetProb.isUnknown())<br>
+    fixBranchProb(MBBInfo->FBB);<br>
+<br>
+  if (CC != X86::COND_E)<br>
+    RemoveList.push_back(&MBB);<br>
+<br>
+  // Invalidate MBBInfo just in case.<br>
+  MBBInfos[MBB.getNumber()] = nullptr;<br>
+  MBBInfos[RootMBB->getNumber()] = nullptr;<br>
+<br>
+  LLVM_DEBUG(dbgs() << "After optimization:\nRootMBB is: " << *RootMBB <br>
+<< "\n");<br>
+  if (BranchPath.size() > 1)<br>
+    LLVM_DEBUG(dbgs() << "PredMBB is: " << *(BranchPath[0]) << "\n"); }<br>
+<br>
+// Driver function for optimization: find the valid candidate and apply <br>
+// the transformation.<br>
+bool X86CondBrFolding::optimize() {<br>
+  bool Changed = false;<br>
+  LLVM_DEBUG(dbgs() << "***** X86CondBr Folding on Function: " << MF.getName()<br>
+                    << " *****\n");<br>
+  // Setup data structures.<br>
+  MBBInfos.resize(MF.getNumBlockIDs());<br>
+  for (auto &MBB : MF)<br>
+    MBBInfos[MBB.getNumber()] = analyzeMBB(MBB);<br>
+<br>
+  for (auto &MBB : MF) {<br>
+    TargetMBBInfo *MBBInfo = getMBBInfo(&MBB);<br>
+    if (!MBBInfo || !MBBInfo->CmpBrOnly)<br>
+      continue;<br>
+    if (MBB.pred_size() != 1)<br>
+      continue;<br>
+    LLVM_DEBUG(dbgs() << "Work on MBB." << MBB.getNumber()<br>
+                      << " CmpValue: " << MBBInfo->CmpValue << "\n");<br>
+    SmallVector<MachineBasicBlock *, 4> BranchPath;<br>
+    if (!findPath(&MBB, BranchPath))<br>
+      continue;<br>
+<br>
+#ifndef NDEBUG<br>
+    LLVM_DEBUG(dbgs() << "Found one path (len=" << BranchPath.size() << "):\n");<br>
+    int Index = 1;<br>
+    LLVM_DEBUG(dbgs() << "Target MBB is: " << MBB << "\n");<br>
+    for (auto I = BranchPath.rbegin(); I != BranchPath.rend(); ++I, ++Index) {<br>
+      MachineBasicBlock *PMBB = *I;<br>
+      TargetMBBInfo *PMBBInfo = getMBBInfo(PMBB);<br>
+      LLVM_DEBUG(dbgs() << "Path MBB (" << Index << " of " << BranchPath.size()<br>
+                        << ") is " << *PMBB);<br>
+      LLVM_DEBUG(dbgs() << "CC=" << PMBBInfo->BranchCode<br>
+                        << "  Val=" << PMBBInfo->CmpValue<br>
+                        << "  CmpBrOnly=" << PMBBInfo->CmpBrOnly << "\n\n");<br>
+    }<br>
+#endif<br>
+    optimizeCondBr(MBB, BranchPath);<br>
+    Changed = true;<br>
+  }<br>
+  NumFixedCondBrs += RemoveList.size();<br>
+  for (auto MBBI : RemoveList) {<br>
+    for (auto *Succ : MBBI->successors())<br>
+      MBBI->removeSuccessor(Succ);<br>
+    MBBI->eraseFromParent();<br>
+  }<br>
+<br>
+  return Changed;<br>
+}<br>
+<br>
+// Analyze instructions that generate CondCode and extract information.<br>
+bool X86CondBrFolding::analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,<br>
+                                      int &CmpValue) {<br>
+  unsigned SrcRegIndex = 0;<br>
+  unsigned ValueIndex = 0;<br>
+  switch (MI.getOpcode()) {<br>
+  // TODO: handle test instructions.<br>
+  default:<br>
+    return false;<br>
+  case X86::CMP64ri32:<br>
+  case X86::CMP64ri8:<br>
+  case X86::CMP32ri:<br>
+  case X86::CMP32ri8:<br>
+  case X86::CMP16ri:<br>
+  case X86::CMP16ri8:<br>
+  case X86::CMP8ri:<br>
+    SrcRegIndex = 0;<br>
+    ValueIndex = 1;<br>
+    break;<br>
+  case X86::SUB64ri32:<br>
+  case X86::SUB64ri8:<br>
+  case X86::SUB32ri:<br>
+  case X86::SUB32ri8:<br>
+  case X86::SUB16ri:<br>
+  case X86::SUB16ri8:<br>
+  case X86::SUB8ri:<br>
+    SrcRegIndex = 1;<br>
+    ValueIndex = 2;<br>
+    break;<br>
+  }<br>
+  SrcReg = MI.getOperand(SrcRegIndex).getReg();<br>
+  assert(MI.getOperand(ValueIndex).isImm() && "Expecting Imm operand");<br>
+  CmpValue = MI.getOperand(ValueIndex).getImm();<br>
+  return true;<br>
+}<br>
+<br>
+// Analyze a candidate MBB and set the extract all the information needed.<br>
+// The valid candidate will have two successors.<br>
+// It also should have a sequence of<br>
+//  Branch_instr,<br>
+//  CondBr,<br>
+//  UnCondBr.<br>
+// Return TargetMBBInfo if MBB is a valid candidate and nullptr otherwise.<br>
+std::unique_ptr<TargetMBBInfo><br>
+X86CondBrFolding::analyzeMBB(MachineBasicBlock &MBB) {<br>
+  MachineBasicBlock *TBB;<br>
+  MachineBasicBlock *FBB;<br>
+  MachineInstr *BrInstr;<br>
+  MachineInstr *CmpInstr;<br>
+  X86::CondCode CC;<br>
+  unsigned SrcReg;<br>
+  int CmpValue;<br>
+  bool Modified;<br>
+  bool CmpBrOnly;<br>
+<br>
+  if (MBB.succ_size() != 2)<br>
+    return nullptr;<br>
+<br>
+  CmpBrOnly = true;<br>
+  FBB = TBB = nullptr;<br>
+  CmpInstr = nullptr;<br>
+  MachineBasicBlock::iterator I = MBB.end();  while (I != MBB.begin()) <br>
+ {<br>
+    --I;<br>
+    if (I->isDebugValue())<br>
+      continue;<br>
+    if (I->getOpcode() == X86::JMP_1) {<br>
+      if (FBB)<br>
+        return nullptr;<br>
+      FBB = I->getOperand(0).getMBB();<br>
+      continue;<br>
+    }<br>
+    if (I->isBranch()) {<br>
+      if (TBB)<br>
+        return nullptr;<br>
+      CC = X86::getCondFromBranchOpc(I->getOpcode());<br>
+      switch (CC) {<br>
+      default:<br>
+        return nullptr;<br>
+      case X86::COND_E:<br>
+      case X86::COND_L:<br>
+      case X86::COND_G:<br>
+      case X86::COND_NE:<br>
+      case X86::COND_LE:<br>
+      case X86::COND_GE:<br>
+        break;<br>
+      }<br>
+      TBB = I->getOperand(0).getMBB();<br>
+      BrInstr = &*I;<br>
+      continue;<br>
+    }<br>
+    if (analyzeCompare(*I, SrcReg, CmpValue)) {<br>
+      if (CmpInstr)<br>
+        return nullptr;<br>
+      CmpInstr = &*I;<br>
+      continue;<br>
+    }<br>
+    CmpBrOnly = false;<br>
+    break;<br>
+  }<br>
+<br>
+  if (!TBB || !FBB || !CmpInstr)<br>
+    return nullptr;<br>
+<br>
+  // Simplify CondCode. Note this is only to simplify the findPath <br>
+logic<br>
+  // and will not change the instruction here.<br>
+  switch (CC) {<br>
+  case X86::COND_NE:<br>
+    CC = X86::COND_E;<br>
+    std::swap(TBB, FBB);<br>
+    Modified = true;<br>
+    break;<br>
+  case X86::COND_LE:<br>
+    if (CmpValue == INT_MAX)<br>
+      return nullptr;<br>
+    CC = X86::COND_L;<br>
+    CmpValue += 1;<br>
+    Modified = true;<br>
+    break;<br>
+  case X86::COND_GE:<br>
+    if (CmpValue == INT_MIN)<br>
+      return nullptr;<br>
+    CC = X86::COND_G;<br>
+    CmpValue -= 1;<br>
+    Modified = true;<br>
+    break;<br>
+  default:<br>
+    Modified = false;<br>
+    break;<br>
+  }<br>
+  return llvm::make_unique<TargetMBBInfo>(TargetMBBInfo{<br>
+      TBB, FBB, BrInstr, CmpInstr, CC, SrcReg, CmpValue, Modified, <br>
+CmpBrOnly}); }<br>
+<br>
+bool X86CondBrFoldingPass::runOnMachineFunction(MachineFunction &MF) {<br>
+  const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();<br>
+  if (!ST.threewayBranchProfitable())<br>
+    return false;<br>
+  const X86InstrInfo *TII = ST.getInstrInfo();<br>
+  const MachineBranchProbabilityInfo *MBPI =<br>
+      &getAnalysis<MachineBranchProbabilityInfo>();<br>
+<br>
+  X86CondBrFolding CondBr(TII, MBPI, MF);<br>
+  return CondBr.optimize();<br>
+}<br>
<br>
Modified: llvm/trunk/lib/Target/X86/X86Subtarget.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86Subtarget.h?rev=344085&r1=344084&r2=344085&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86Subtarget.h?rev=344085&r1=344084&r2=344085&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/X86/X86Subtarget.h (original)<br>
+++ llvm/trunk/lib/Target/X86/X86Subtarget.h Tue Oct  9 15:03:40 2018<br>
@@ -419,6 +419,9 @@ protected:<br>
   /// Indicates target prefers 256 bit instructions.<br>
   bool Prefer256Bit = false;<br>
<br>
+  /// Threeway branch is profitable in this subtarget.<br>
+  bool ThreewayBranchProfitable = false;<br>
+<br>
   /// What processor and OS we're targeting.<br>
   Triple TargetTriple;<br>
<br>
@@ -662,6 +665,7 @@ public:<br>
   bool hasWAITPKG() const { return HasWAITPKG; }<br>
   bool hasPCONFIG() const { return HasPCONFIG; }<br>
   bool hasSGX() const { return HasSGX; }<br>
+  bool threewayBranchProfitable() const { return <br>
+ ThreewayBranchProfitable; }<br>
   bool hasINVPCID() const { return HasINVPCID; }<br>
   bool useRetpolineIndirectCalls() const { return UseRetpolineIndirectCalls; }<br>
   bool useRetpolineIndirectBranches() const {<br>
<br>
Modified: llvm/trunk/lib/Target/X86/X86TargetMachine.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetMachine.cpp?rev=344085&r1=344084&r2=344085&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetMachine.cpp?rev=344085&r1=344084&r2=344085&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/X86/X86TargetMachine.cpp (original)<br>
+++ llvm/trunk/lib/Target/X86/X86TargetMachine.cpp Tue Oct  9 15:03:40 <br>
+++ 2018<br>
@@ -54,6 +54,11 @@ static cl::opt<bool> EnableMachineCombin<br>
                                cl::desc("Enable the machine combiner pass"),<br>
                                cl::init(true), cl::Hidden);<br>
<br>
+static cl::opt<bool> EnableCondBrFoldingPass("x86-condbr-folding",<br>
+                               cl::desc("Enable the conditional branch "<br>
+                                        "folding pass"),<br>
+                               cl::init(true), cl::Hidden);<br>
+<br>
 namespace llvm {<br>
<br>
 void initializeWinEHStatePassPass(PassRegistry &); @@ -447,6 +452,8 @@ bool X86PassConfig::addGlobalInstruction<br>
 }<br>
<br>
 bool X86PassConfig::addILPOpts() {<br>
+  if (EnableCondBrFoldingPass)<br>
+    addPass(createX86CondBrFolding());<br>
   addPass(&EarlyIfConverterID);<br>
   if (EnableMachineCombinerPass)<br>
     addPass(&MachineCombinerID);<br>
<br>
Modified: llvm/trunk/test/CodeGen/X86/O3-pipeline.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/O3-pipeline.ll?rev=344085&r1=344084&r2=344085&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/O3-pipeline.ll?rev=344085&r1=344084&r2=344085&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/CodeGen/X86/O3-pipeline.ll (original)<br>
+++ llvm/trunk/test/CodeGen/X86/O3-pipeline.ll Tue Oct  9 15:03:40 2018<br>
@@ -72,6 +72,7 @@<br>
 ; CHECK-NEXT:       Merge disjoint stack slots<br>
 ; CHECK-NEXT:       Local Stack Slot Allocation<br>
 ; CHECK-NEXT:       Remove dead machine instructions<br>
+; CHECK-NEXT:       X86 CondBr Folding<br>
 ; CHECK-NEXT:       MachineDominator Tree Construction<br>
 ; CHECK-NEXT:       Machine Natural Loop Construction<br>
 ; CHECK-NEXT:       Machine Trace Metrics<br>
<br>
Added: llvm/trunk/test/CodeGen/X86/condbr_if.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/condbr_if.ll?rev=344085&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/condbr_if.ll?rev=344085&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/CodeGen/X86/condbr_if.ll (added)<br>
+++ llvm/trunk/test/CodeGen/X86/condbr_if.ll Tue Oct  9 15:03:40 2018<br>
@@ -0,0 +1,178 @@<br>
+; RUN: llc -mtriple=x86_64-linux-gnu -mcpu=sandybridge %s -o - <br>
+-verify-machineinstrs | FileCheck %s --check-prefix=MERGE ; RUN: llc <br>
+-mtriple=x86_64-linux-gnu -mcpu=ivybridge %s -o - -verify-machineinstrs <br>
+| FileCheck %s --check-prefix=MERGE ; RUN: llc <br>
+-mtriple=x86_64-linux-gnu -mcpu=haswell %s -o - -verify-machineinstrs | <br>
+FileCheck %s --check-prefix=MERGE ; RUN: llc -mtriple=x86_64-linux-gnu <br>
+-mcpu=broadwell %s -o - -verify-machineinstrs | FileCheck %s <br>
+--check-prefix=MERGE ; RUN: llc -mtriple=x86_64-linux-gnu -mcpu=skylake <br>
+%s -o - -verify-machineinstrs | FileCheck %s --check-prefix=MERGE ; <br>
+RUN: llc -mtriple=x86_64-linux-gnu -mcpu=skx %s -o - <br>
+-verify-machineinstrs | FileCheck %s --check-prefix=MERGE ; RUN: llc <br>
+-mtriple=x86_64-linux-gnu %s -o - -verify-machineinstrs | FileCheck %s <br>
+--check-prefix=NOTMERGE<br>
+<br>
+define i32 @length2_1(i32) {<br>
+  %2 = icmp slt i32 %0, 3<br>
+  br i1 %2, label %3, label %5<br>
+<br>
+; <label>:3:<br>
+  %4 = tail call i32 (...) @f1()<br>
+  br label %13<br>
+<br>
+; <label>:5:<br>
+  %6 = icmp slt i32 %0, 40<br>
+  br i1 %6, label %7, label %13<br>
+<br>
+; <label>:7:<br>
+  %8 = icmp eq i32 %0, 3<br>
+  br i1 %8, label %9, label %11<br>
+<br>
+; <label>:9:<br>
+  %10 = tail call i32 (...) @f2()<br>
+  br label %11<br>
+<br>
+; <label>:11:<br>
+  %12 = tail call i32 (...) @f3() #2<br>
+  br label %13<br>
+<br>
+; <label>:13:<br>
+  ret i32 0<br>
+}<br>
+; MERGE-LABEL: length2_1<br>
+; MERGE: cmpl $3<br>
+; MERGE-NEXT: jg<br>
+; MERGE-NEXT: jge<br>
+; NOTMERGE-LABEL: length2_1<br>
+; NOTMERGE: cmpl $2<br>
+; NOTMERGE-NEXT: jg<br>
+<br>
+define i32 @length2_2(i32) {<br>
+  %2 = icmp sle i32 %0, 2<br>
+  br i1 %2, label %3, label %5<br>
+<br>
+; <label>:3:<br>
+  %4 = tail call i32 (...) @f1()<br>
+  br label %13<br>
+<br>
+; <label>:5:<br>
+  %6 = icmp slt i32 %0, 40<br>
+  br i1 %6, label %7, label %13<br>
+<br>
+; <label>:7:<br>
+  %8 = icmp eq i32 %0, 3<br>
+  br i1 %8, label %9, label %11<br>
+<br>
+; <label>:9:<br>
+  %10 = tail call i32 (...) @f2()<br>
+  br label %11<br>
+<br>
+; <label>:11:<br>
+  %12 = tail call i32 (...) @f3() #2<br>
+  br label %13<br>
+<br>
+; <label>:13:<br>
+  ret i32 0<br>
+}<br>
+; MERGE-LABEL: length2_2<br>
+; MERGE: cmpl $3<br>
+; MERGE-NEXT: jg<br>
+; MERGE-NEXT: jge<br>
+; NOTMERGE-LABEL: length2_2<br>
+; NOTMERGE: cmpl $2<br>
+; NOTMERGE-NEXT: jg<br>
+<br>
+define i32 @length2_3(i32) {<br>
+  %2 = icmp sgt i32 %0, 3<br>
+  br i1 %2, label %3, label %5<br>
+<br>
+; <label>:3:<br>
+  %4 = tail call i32 (...) @f1()<br>
+  br label %13<br>
+<br>
+; <label>:5:<br>
+  %6 = icmp sgt i32 %0, -40<br>
+  br i1 %6, label %7, label %13<br>
+<br>
+; <label>:7:<br>
+  %8 = icmp eq i32 %0, 3<br>
+  br i1 %8, label %9, label %11<br>
+<br>
+; <label>:9:<br>
+  %10 = tail call i32 (...) @f2()<br>
+  br label %11<br>
+<br>
+; <label>:11:<br>
+  %12 = tail call i32 (...) @f3() #2<br>
+  br label %13<br>
+<br>
+; <label>:13:<br>
+  ret i32 0<br>
+}<br>
+; MERGE-LABEL: length2_3<br>
+; MERGE: cmpl $3<br>
+; MERGE-NEXT: jl<br>
+; MERGE-NEXT: jle<br>
+; NOTMERGE-LABEL: length2_3<br>
+; NOTMERGE: cmpl $4<br>
+; NOTMERGE-NEXT: jl<br>
+<br>
+define i32 @length2_4(i32) {<br>
+  %2 = icmp sge i32 %0, 4<br>
+  br i1 %2, label %3, label %5<br>
+<br>
+; <label>:3:<br>
+  %4 = tail call i32 (...) @f1()<br>
+  br label %13<br>
+<br>
+; <label>:5:<br>
+  %6 = icmp sgt i32 %0, -40<br>
+  br i1 %6, label %7, label %13<br>
+<br>
+; <label>:7:<br>
+  %8 = icmp eq i32 %0, 3<br>
+  br i1 %8, label %9, label %11<br>
+<br>
+; <label>:9:<br>
+  %10 = tail call i32 (...) @f2()<br>
+  br label %11<br>
+<br>
+; <label>:11:<br>
+  %12 = tail call i32 (...) @f3() #2<br>
+  br label %13<br>
+<br>
+; <label>:13:<br>
+  ret i32 0<br>
+}<br>
+; MERGE-LABEL: length2_4<br>
+; MERGE: cmpl $3<br>
+; MERGE-NEXT: jl<br>
+; MERGE-NEXT: jle<br>
+; NOTMERGE-LABEL: length2_4<br>
+; NOTMERGE: cmpl $4<br>
+; NOTMERGE-NEXT: jl<br>
+<br>
+declare i32 @f1(...)<br>
+declare i32 @f2(...)<br>
+declare i32 @f3(...)<br>
+<br>
+define i32 @length1_1(i32) {<br>
+  %2 = icmp sgt i32 %0, 5<br>
+  br i1 %2, label %3, label %5<br>
+<br>
+; <label>:3:<br>
+  %4 = tail call i32 (...) @f1()<br>
+  br label %9<br>
+<br>
+; <label>:5:<br>
+  %6 = icmp eq i32 %0, 5<br>
+  br i1 %6, label %7, label %9<br>
+<br>
+; <label>:7:<br>
+  %8 = tail call i32 (...) @f2()<br>
+  br label %9<br>
+<br>
+; <label>:9:<br>
+  ret i32 0<br>
+}<br>
+; MERGE-LABEL: length1_1<br>
+; MERGE: cmpl $5<br>
+; MERGE-NEXT: jl<br>
+; MERGE-NEXT: jle<br>
+; NOTMERGE-LABEL: length1_1<br>
+; NOTMERGE: cmpl $6<br>
+; NOTMERGE-NEXT: jl<br>
<br>
Added: llvm/trunk/test/CodeGen/X86/condbr_switch.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/condbr_switch.ll?rev=344085&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/condbr_switch.ll?rev=344085&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/CodeGen/X86/condbr_switch.ll (added)<br>
+++ llvm/trunk/test/CodeGen/X86/condbr_switch.ll Tue Oct  9 15:03:40 <br>
+++ 2018<br>
@@ -0,0 +1,167 @@<br>
+; RUN: llc -mtriple=x86_64-linux-gnu -mcpu=sandybridge %s -o - <br>
+-verify-machineinstrs | FileCheck %s --check-prefix=MERGE ; RUN: llc <br>
+-mtriple=x86_64-linux-gnu -mcpu=ivybridge %s -o - -verify-machineinstrs <br>
+| FileCheck %s --check-prefix=MERGE ; RUN: llc <br>
+-mtriple=x86_64-linux-gnu -mcpu=haswell %s -o - -verify-machineinstrs | <br>
+FileCheck %s --check-prefix=MERGE ; RUN: llc -mtriple=x86_64-linux-gnu <br>
+-mcpu=broadwell %s -o - -verify-machineinstrs | FileCheck %s <br>
+--check-prefix=MERGE ; RUN: llc -mtriple=x86_64-linux-gnu -mcpu=skylake <br>
+%s -o - -verify-machineinstrs | FileCheck %s --check-prefix=MERGE ; <br>
+RUN: llc -mtriple=x86_64-linux-gnu -mcpu=skx %s -o - <br>
+-verify-machineinstrs | FileCheck %s --check-prefix=MERGE ; RUN: llc <br>
+-mtriple=x86_64-linux-gnu %s -o - -verify-machineinstrs | FileCheck %s <br>
+--check-prefix=NOTMERGE<br>
+<br>
+@v1 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v2 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v3 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v4 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v5 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v6 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v7 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v8 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v9 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v10 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v11 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v12 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v13 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v14 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+@v15 = common dso_local local_unnamed_addr global i32 0, align 4<br>
+<br>
+define dso_local i32 @fourcases(i32 %n) {<br>
+entry:<br>
+  switch i32 %n, label %return [<br>
+    i32 111, label %<a href="http://sw.bb" rel="noreferrer" target="_blank">sw.bb</a><br>
+    i32 222, label %sw.bb1<br>
+    i32 3665, label %sw.bb2<br>
+    i32 4444, label %sw.bb4<br>
+  ]<br>
+<br>
+<a href="http://sw.bb" rel="noreferrer" target="_blank">sw.bb</a>:<br>
+  %0 = load i32, i32* @v1, align 4<br>
+  br label %return<br>
+<br>
+sw.bb1:<br>
+  %1 = load i32, i32* @v2, align 4<br>
+  %add = add nsw i32 %1, 12<br>
+  br label %return<br>
+<br>
+sw.bb2:<br>
+  %2 = load i32, i32* @v3, align 4<br>
+  %add3 = add nsw i32 %2, 13<br>
+  br label %return<br>
+<br>
+sw.bb4:<br>
+  %3 = load i32, i32* @v1, align 4<br>
+  %4 = load i32, i32* @v2, align 4<br>
+  %add5 = add nsw i32 %4, %3<br>
+  br label %return<br>
+<br>
+return:<br>
+  %retval.0 = phi i32 [ %add5, %sw.bb4 ], [ %add3, %sw.bb2 ], [ %add, <br>
+%sw.bb1 ], [ %0, %<a href="http://sw.bb" rel="noreferrer" target="_blank">sw.bb</a> ], [ 0, %entry ]<br>
+  ret i32 %retval.0<br>
+}<br>
+; MERGE-LABEL: fourcases<br>
+; MERGE: cmpl $3665<br>
+; MERGE-NEXT: jg<br>
+; MERGE-NEXT: jge<br>
+; NOTMERGE: cmpl $3664<br>
+; NOTMERGE-NEXT: jg<br>
+<br>
+define dso_local i32 @fifteencases(i32) {<br>
+  switch i32 %0, label %32 [<br>
+    i32 -111, label %2<br>
+    i32 -13, label %4<br>
+    i32 25, label %6<br>
+    i32 37, label %8<br>
+    i32 89, label %10<br>
+    i32 111, label %12<br>
+    i32 213, label %14<br>
+    i32 271, label %16<br>
+    i32 283, label %18<br>
+    i32 325, label %20<br>
+    i32 327, label %22<br>
+    i32 429, label %24<br>
+    i32 500, label %26<br>
+    i32 603, label %28<br>
+    i32 605, label %30<br>
+  ]<br>
+<br>
+; <label>:2<br>
+  %3 = load i32, i32* @v1, align 4<br>
+  br label %32<br>
+<br>
+; <label>:4<br>
+  %5 = load i32, i32* @v2, align 4<br>
+  br label %32<br>
+<br>
+; <label>:6<br>
+  %7 = load i32, i32* @v3, align 4<br>
+  br label %32<br>
+<br>
+; <label>:8<br>
+  %9 = load i32, i32* @v4, align 4<br>
+  br label %32<br>
+<br>
+; <label>:10<br>
+  %11 = load i32, i32* @v5, align 4<br>
+  br label %32<br>
+<br>
+; <label>:12<br>
+  %13 = load i32, i32* @v6, align 4<br>
+  br label %32<br>
+<br>
+; <label>:14<br>
+  %15 = load i32, i32* @v7, align 4<br>
+  br label %32<br>
+<br>
+; <label>:16<br>
+  %17 = load i32, i32* @v8, align 4<br>
+  br label %32<br>
+<br>
+; <label>:18<br>
+  %19 = load i32, i32* @v9, align 4<br>
+  br label %32<br>
+<br>
+; <label>:20<br>
+  %21 = load i32, i32* @v10, align 4<br>
+  br label %32<br>
+<br>
+; <label>:22<br>
+  %23 = load i32, i32* @v11, align 4<br>
+  br label %32<br>
+<br>
+; <label>:24<br>
+  %25 = load i32, i32* @v12, align 4<br>
+  br label %32<br>
+<br>
+; <label>:26<br>
+  %27 = load i32, i32* @v13, align 4<br>
+  br label %32<br>
+<br>
+; <label>:28:<br>
+  %29 = load i32, i32* @v14, align 4<br>
+  br label %32<br>
+<br>
+; <label>:30:<br>
+  %31 = load i32, i32* @v15, align 4<br>
+  br label %32<br>
+<br>
+; <label>:32:<br>
+  %33 = phi i32 [ %31, %30 ], [ %29, %28 ], [ %27, %26 ], [ %25, %24 ], <br>
+[ %23, %22 ], [ %21, %20 ], [ %19, %18 ], [ %17, %16 ], [ %15, %14 ], [ <br>
+%13, %12 ], [ %11, %10 ], [ %9, %8 ], [ %7, %6 ], [ %5, %4 ], [ %3, %2 <br>
+], [ 0, %1 ]<br>
+  ret i32 %33<br>
+}<br>
+; MERGE-LABEL: fifteencases<br>
+; MERGE: cmpl $271<br>
+; MERGE-NEXT: jg<br>
+; MERGE-NEXT: jge<br>
+; MERGE: cmpl $37<br>
+; MERGE-NEXT: jg<br>
+; MERGE-NEXT: jge<br>
+; MERGE: cmpl $429<br>
+; MERGE-NEXT: jg<br>
+; MERGE-NEXT: jge<br>
+; MERGE: cmpl $325<br>
+; MERGE-NEXT: jg<br>
+; MERGE-NEXT: jge<br>
+; MERGE: cmpl $603<br>
+; MERGE-NEXT: jg<br>
+; MERGE-NEXT: jge<br>
+; NOTMERGE-LABEL: fifteencases<br>
+; NOTMERGE: cmpl $270<br>
+; NOTMERGE-NEXT: jle<br>
+<br>
<br>
<br>
_______________________________________________<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/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>