[llvm] [X86] Add post-RA redundant copy elimination for TEST/CMP branch paths (PR #203733)

via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 13 17:22:12 PDT 2026


https://github.com/mike-goutokuji created https://github.com/llvm/llvm-project/pull/203733

Like AArch64 and RISC-V.

>From 9a6d7c34096d368a9439db32eedf4b36aed083cc Mon Sep 17 00:00:00 2001
From: Mike-Goutokuji <83477269+mike-goutokuji at users.noreply.github.com>
Date: Sat, 13 Jun 2026 18:59:41 -0400
Subject: [PATCH] [X86] Add post-RA redundant copy elimination for TEST/CMP
 branch paths

Like AArch64 and RISC-V.
---
 llvm/lib/Target/X86/CMakeLists.txt            |   1 +
 llvm/lib/Target/X86/X86.h                     |  14 +
 llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp |   3 +
 llvm/lib/Target/X86/X86PassRegistry.def       |   1 +
 .../X86/X86RedundantCopyElimination.cpp       | 395 ++++++++++++++++++
 llvm/lib/Target/X86/X86TargetMachine.cpp      |   4 +
 .../CodeGen/X86/apx/memfold-origVNI-crash.ll  |   4 +-
 llvm/test/CodeGen/X86/coalescer-commute3.ll   |   8 +-
 llvm/test/CodeGen/X86/conditional-tailcall.ll |   1 -
 llvm/test/CodeGen/X86/llc-pipeline-npm.ll     |   2 +
 .../CodeGen/X86/machine-zero-copy-remove.mir  | 277 ++++++++++++
 llvm/test/CodeGen/X86/opt-pipeline.ll         |   2 +
 llvm/test/CodeGen/X86/pr38795.ll              |   2 -
 llvm/test/CodeGen/X86/switch.ll               | 167 ++++----
 .../gn/secondary/llvm/lib/Target/X86/BUILD.gn |   1 +
 15 files changed, 783 insertions(+), 99 deletions(-)
 create mode 100644 llvm/lib/Target/X86/X86RedundantCopyElimination.cpp
 create mode 100644 llvm/test/CodeGen/X86/machine-zero-copy-remove.mir

diff --git a/llvm/lib/Target/X86/CMakeLists.txt b/llvm/lib/Target/X86/CMakeLists.txt
index 62987bdbd1c2b..7e0918dad176b 100644
--- a/llvm/lib/Target/X86/CMakeLists.txt
+++ b/llvm/lib/Target/X86/CMakeLists.txt
@@ -54,6 +54,7 @@ set(sources
   X86DynAllocaExpander.cpp
   X86FixupSetCC.cpp
   X86FlagsCopyLowering.cpp
+  X86RedundantCopyElimination.cpp
   X86FloatingPoint.cpp
   X86FrameLowering.cpp
   X86ISelDAGToDAG.cpp
diff --git a/llvm/lib/Target/X86/X86.h b/llvm/lib/Target/X86/X86.h
index 3ecc7a6ec498b..93ce34170818f 100644
--- a/llvm/lib/Target/X86/X86.h
+++ b/llvm/lib/Target/X86/X86.h
@@ -20,10 +20,13 @@
 #include "llvm/IR/PassManager.h"
 #include "llvm/PassInfo.h"
 #include "llvm/Support/CodeGen.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Target/TargetMachine.h"
 
 namespace llvm {
 
+extern cl::opt<bool> EnableRedundantCopyElimination;
+
 class FunctionPass;
 class InstructionSelector;
 class PassRegistry;
@@ -224,6 +227,16 @@ class X86LowerTileCopyPass
 
 FunctionPass *createX86LowerTileCopyLegacyPass();
 
+/// Remove redundant copies/moves based on dominating branch conditions.
+class X86RedundantCopyEliminationPass
+    : public OptionalPassInfoMixin<X86RedundantCopyEliminationPass> {
+public:
+  PreservedAnalyses run(MachineFunction &MF,
+                        MachineFunctionAnalysisManager &MFAM);
+};
+
+FunctionPass *createX86RedundantCopyEliminationLegacyPass();
+
 /// Return a pass that inserts int3 at the end of the function if it ends with a
 /// CALL instruction. The pass does the same for each funclet as well. This
 /// ensures that the open interval of function start and end PCs contains all
@@ -498,6 +511,7 @@ void initializeX86LoadValueInjectionRetHardeningLegacyPass(PassRegistry &);
 void initializeX86LowerAMXIntrinsicsLegacyPassPass(PassRegistry &);
 void initializeX86LowerAMXTypeLegacyPassPass(PassRegistry &);
 void initializeX86LowerTileCopyLegacyPass(PassRegistry &);
+void initializeX86RedundantCopyEliminationLegacyPass(PassRegistry &);
 void initializeX86OptimizeLEAsLegacyPass(PassRegistry &);
 void initializeX86PartialReductionLegacyPass(PassRegistry &);
 void initializeX86PreTileConfigLegacyPass(PassRegistry &);
diff --git a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
index bb389b6756a52..f240e10698375 100644
--- a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
@@ -163,6 +163,9 @@ void X86CodeGenPassBuilder::addPreRegAlloc(PassManagerWrapper &PMW) const {
 }
 
 void X86CodeGenPassBuilder::addPostRegAlloc(PassManagerWrapper &PMW) const {
+  if (getOptLevel() != CodeGenOptLevel::None &&
+      EnableRedundantCopyElimination)
+    addMachineFunctionPass(X86RedundantCopyEliminationPass(), PMW);
   addMachineFunctionPass(X86LowerTileCopyPass(), PMW);
   addMachineFunctionPass(X86FPStackifierPass(), PMW);
   // When -O0 is enabled, the Load Value Injection Hardening pass will fall back
diff --git a/llvm/lib/Target/X86/X86PassRegistry.def b/llvm/lib/Target/X86/X86PassRegistry.def
index 45e7d0ebdbf7b..55047bedad6bc 100644
--- a/llvm/lib/Target/X86/X86PassRegistry.def
+++ b/llvm/lib/Target/X86/X86PassRegistry.def
@@ -47,6 +47,7 @@ MACHINE_FUNCTION_PASS("x86-fixup-leas", X86FixupLEAsPass())
 MACHINE_FUNCTION_PASS("x86-fixup-setcc", X86FixupSetCCPass())
 MACHINE_FUNCTION_PASS("x86-fixup-vector-constants", X86FixupVectorConstantsPass())
 MACHINE_FUNCTION_PASS("x86-flags-copy-lowering", X86FlagsCopyLoweringPass())
+MACHINE_FUNCTION_PASS("x86-copyelim", X86RedundantCopyEliminationPass())
 MACHINE_FUNCTION_PASS("x86-fp-stackifier", X86FPStackifierPass())
 MACHINE_FUNCTION_PASS("x86-global-base-reg", X86GlobalBaseRegPass())
 MACHINE_FUNCTION_PASS("x86-indirect-branch-tracking", X86IndirectBranchTrackingPass())
diff --git a/llvm/lib/Target/X86/X86RedundantCopyElimination.cpp b/llvm/lib/Target/X86/X86RedundantCopyElimination.cpp
new file mode 100644
index 0000000000000..46bb7577dba72
--- /dev/null
+++ b/llvm/lib/Target/X86/X86RedundantCopyElimination.cpp
@@ -0,0 +1,395 @@
+
+//=- X86RedundantCopyElimination.cpp - Remove useless copy for X86 ----------=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86.h"
+#include "X86InstrInfo.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "x86-copyelim"
+
+STATISTIC(NumCopiesRemoved, "Number of copies removed.");
+
+namespace llvm {
+cl::opt<bool> EnableRedundantCopyElimination(
+    "x86-enable-copyelim",
+    cl::desc("Enable the redundant copy elimination pass"), cl::init(true),
+    cl::Hidden);
+} // namespace llvm
+
+namespace {
+
+struct KnownValue {
+  bool IsReg;
+  union {
+    MCPhysReg Reg;
+    int64_t Imm;
+  } U;
+
+  KnownValue() : IsReg(false) { U.Imm = 0; }
+  KnownValue(MCPhysReg R) : IsReg(true) { U.Reg = R; }
+  KnownValue(int64_t I) : IsReg(false) { U.Imm = I; }
+};
+
+static bool isRedundantZeroDefinition(const MachineInstr &MI) {
+  if (MI.getOpcode() == X86::MOV32r0)
+    return true;
+  if (MI.isMoveImmediate())
+    return MI.getOperand(1).isImm() && MI.getOperand(1).getImm() == 0;
+  switch (MI.getOpcode()) {
+  case X86::XOR8rr:
+  case X86::XOR16rr:
+  case X86::XOR32rr:
+  case X86::XOR64rr:
+    return MI.getOperand(1).getReg() == MI.getOperand(2).getReg();
+  default:
+    return false;
+  }
+}
+
+class X86RedundantCopyEliminationImpl {
+public:
+  X86RedundantCopyEliminationImpl() {}
+  bool run(MachineFunction &MF);
+
+private:
+
+  const TargetRegisterInfo *TRI;
+  const TargetInstrInfo *TII;
+
+  bool optimizeBlock(MachineBasicBlock &MBB);
+};
+
+class X86RedundantCopyEliminationLegacy : public MachineFunctionPass {
+public:
+  static char ID;
+  X86RedundantCopyEliminationLegacy() : MachineFunctionPass(ID) {}
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+
+  MachineFunctionProperties getRequiredProperties() const override {
+    return MachineFunctionProperties().setNoVRegs();
+  }
+  StringRef getPassName() const override {
+    return "X86 Redundant Copy Elimination";
+  }
+};
+
+bool X86RedundantCopyEliminationImpl::optimizeBlock(MachineBasicBlock &MBB) {
+  if (MBB.pred_size() != 1)
+    return false;
+
+  MachineBasicBlock *BranchMBB = *MBB.pred_begin();
+  SmallVector<MachineBasicBlock *, 4> Path;
+
+  // Trace back along single-predecessor edges.
+  while (BranchMBB->succ_size() != 2) {
+    if (BranchMBB->pred_size() != 1)
+      return false;
+    Path.push_back(BranchMBB);
+    BranchMBB = *BranchMBB->pred_begin();
+  }
+
+  MachineBasicBlock *TBB = nullptr;
+  MachineBasicBlock *FBB = nullptr;
+  SmallVector<MachineOperand, 4> Cond;
+  if (TII->analyzeBranch(*BranchMBB, TBB, FBB, Cond, /*AllowModify=*/false) ||
+      Cond.size() != 1)
+    return false;
+
+  X86::CondCode CC = static_cast<X86::CondCode>(Cond[0].getImm());
+  
+  MachineBasicBlock *NextOnPath = Path.empty() ? &MBB : Path.back();
+  bool IsTruePath = (NextOnPath == TBB);
+  if (!IsTruePath) {
+    if (FBB) {
+      if (NextOnPath != FBB)
+        return false;
+    } else if (NextOnPath != BranchMBB->getNextNode()) {
+      return false;
+    }
+  }
+
+  MachineInstr *CondBr = nullptr;
+  for (MachineInstr &Term : BranchMBB->terminators()) {
+    if (X86::isJCC(Term.getOpcode())) {
+      CondBr = &Term;
+      break;
+    }
+  }
+  if (!CondBr)
+    return false;
+
+  // Find the flag-setting instruction
+  MachineInstr *FlagSetter = nullptr;
+  MachineBasicBlock::reverse_iterator RIt = CondBr->getReverseIterator();
+  for (MachineInstr &PredI : make_range(std::next(RIt), BranchMBB->rend())) {
+    if (PredI.modifiesRegister(X86::EFLAGS, TRI)) {
+      FlagSetter = &PredI;
+      break;
+    }
+  }
+  if (!FlagSetter)
+    return false;
+
+  SmallVector<std::pair<MCPhysReg, KnownValue>, 4> KnownRegs;
+
+  // Helper: is the equality/zero path taken?
+  bool IsEqualPath = (CC == X86::COND_E && IsTruePath) ||
+                     (CC == X86::COND_NE && !IsTruePath);
+
+  // Analyze the flag setter.
+  switch (FlagSetter->getOpcode()) {
+  default:
+    break;
+
+  // TEST is BinOpRR_F: (outs), (ins $src1, $src2) — no destination register.
+  // Operand 0 = $src1, Operand 1 = $src2.
+  case X86::TEST8rr: case X86::TEST16rr:
+  case X86::TEST32rr: case X86::TEST64rr:
+    if (FlagSetter->getOperand(0).getReg() ==
+        FlagSetter->getOperand(1).getReg()) {
+      if (IsEqualPath)
+        KnownRegs.push_back(
+            {FlagSetter->getOperand(0).getReg(), KnownValue((int64_t)0)});
+    }
+    break;
+
+  // AND/OR are BinOpRR_RF: (outs $dst), (ins $src1, $src2).
+  // Operand 0 = $dst (tied to $src1), Operand 1 = $src1, Operand 2 = $src2.
+  // Self-AND/OR (src1 == src2) sets ZF iff the value is zero.
+  case X86::AND8rr: case X86::AND16rr:
+  case X86::AND32rr: case X86::AND64rr:
+  case X86::OR8rr: case X86::OR16rr:
+  case X86::OR32rr: case X86::OR64rr:
+    if (FlagSetter->getOperand(1).getReg() ==
+        FlagSetter->getOperand(2).getReg()) {
+      if (IsEqualPath)
+        KnownRegs.push_back(
+            {FlagSetter->getOperand(0).getReg(), KnownValue((int64_t)0)});
+    }
+    break;
+
+  // CMP reg, reg is BinOpRR_F: (outs), (ins $src1, $src2).
+  // If equal, $src1 == $src2.
+  case X86::CMP8rr: case X86::CMP16rr:
+  case X86::CMP32rr: case X86::CMP64rr:
+    if (IsEqualPath) {
+      KnownRegs.push_back({FlagSetter->getOperand(0).getReg(),
+                        KnownValue((MCPhysReg)FlagSetter->getOperand(1).getReg())});
+      KnownRegs.push_back({FlagSetter->getOperand(1).getReg(),
+                        KnownValue((MCPhysReg)FlagSetter->getOperand(0).getReg())});
+    }
+    break;
+
+  // CMP reg, imm: (outs), (ins $src1, $imm).
+  // If equal, $src1 == $imm.
+  case X86::CMP8ri: case X86::CMP16ri: case X86::CMP16ri8:
+  case X86::CMP32ri: case X86::CMP32ri8:
+  case X86::CMP64ri8: case X86::CMP64ri32:
+    if (IsEqualPath && FlagSetter->getOperand(1).isImm()) {
+      int64_t Imm = FlagSetter->getOperand(1).getImm();
+      KnownRegs.push_back(
+          {FlagSetter->getOperand(0).getReg(), KnownValue(Imm)});
+    }
+    break;
+
+  // SUB reg, reg is BinOpRR_RF: (outs $dst), (ins $src1, $src2).
+  // If ZF set, $dst is zero. (Note: src1 and src2 were equal before the instruction,
+  // but $dst is tied to $src1, so $src1 is overwritten with zero and no longer equals $src2).
+  case X86::SUB8rr: case X86::SUB16rr:
+  case X86::SUB32rr: case X86::SUB64rr:
+    if (IsEqualPath) {
+      KnownRegs.push_back(
+          {FlagSetter->getOperand(0).getReg(), KnownValue((int64_t)0)});
+    }
+    break;
+  }
+
+  if (KnownRegs.empty())
+    return false;
+
+  // Check if any known register was clobbered in the path.
+  auto isClobbered = [&](MCPhysReg Reg) {
+    // Check BranchMBB from FlagSetter to end
+    for (MachineInstr &MI : make_range(std::next(MachineBasicBlock::iterator(FlagSetter)), BranchMBB->end())) {
+      if (MI.modifiesRegister(Reg, TRI)) return true;
+    }
+    // Check Path blocks
+    for (auto *PMBB : llvm::reverse(Path)) {
+      for (MachineInstr &MI : *PMBB) {
+        if (MI.modifiesRegister(Reg, TRI)) return true;
+      }
+    }
+    return false;
+  };
+
+  for (unsigned i = 0; i < KnownRegs.size();) {
+    if (isClobbered(KnownRegs[i].first) ||
+        (KnownRegs[i].second.IsReg && isClobbered(KnownRegs[i].second.U.Reg))) {
+      KnownRegs[i] = KnownRegs.back();
+      KnownRegs.pop_back();
+    } else {
+      ++i;
+    }
+  }
+
+  if (KnownRegs.empty())
+    return false;
+
+  bool Changed = false;
+  MachineBasicBlock::iterator LastChange = MBB.begin();
+  
+  SmallVector<MCPhysReg, 4> OptimizedRegs;
+
+  for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) {
+    MachineInstr *MI = &*I;
+    ++I;
+
+    // Optimization 1: Remove redundant immediate definitions.
+    // This covers zero-idioms (XOR reg, reg; MOV32r0; MOV reg, 0) as well as
+    // move-immediates matching a known constant from CMP reg, imm.
+    if (isRedundantZeroDefinition(*MI)) {
+      Register DefReg = MI->getOperand(0).getReg();
+      auto It = llvm::find_if(KnownRegs, [&](const std::pair<MCPhysReg, KnownValue> &K) {
+        return K.first == DefReg;
+      });
+      if (It != KnownRegs.end() && !It->second.IsReg && It->second.U.Imm == 0) {
+        LLVM_DEBUG(dbgs() << "Remove redundant zero definition: " << *MI);
+        MI->eraseFromParent();
+        Changed = true;
+        LastChange = I;
+        ++NumCopiesRemoved;
+        OptimizedRegs.push_back(DefReg);
+        continue;
+      }
+    } else if (MI->isMoveImmediate() && MI->getOperand(1).isImm()) {
+      Register DefReg = MI->getOperand(0).getReg();
+      int64_t MIImm = MI->getOperand(1).getImm();
+      auto It = llvm::find_if(KnownRegs, [&](const std::pair<MCPhysReg, KnownValue> &K) {
+        return K.first == DefReg;
+      });
+      if (It != KnownRegs.end() && !It->second.IsReg &&
+          It->second.U.Imm == MIImm) {
+        LLVM_DEBUG(dbgs() << "Remove redundant immediate definition: " << *MI);
+        MI->eraseFromParent();
+        Changed = true;
+        LastChange = I;
+        ++NumCopiesRemoved;
+        OptimizedRegs.push_back(DefReg);
+        continue;
+      }
+    }
+
+    // Optimization 2: Remove redundant register copies/moves.
+    if (MI->isCopy() || MI->isMoveReg()) {
+      Register DefReg = MI->getOperand(0).getReg();
+      Register SrcReg = MI->getOperand(1).getReg();
+      auto It = llvm::find_if(KnownRegs, [&](const std::pair<MCPhysReg, KnownValue> &K) {
+        return K.first == DefReg;
+      });
+      if (It != KnownRegs.end() && It->second.IsReg && It->second.U.Reg == SrcReg) {
+        LLVM_DEBUG(dbgs() << "Remove redundant register copy: " << *MI);
+        MI->eraseFromParent();
+        Changed = true;
+        LastChange = I;
+        ++NumCopiesRemoved;
+        OptimizedRegs.push_back(DefReg);
+        continue;
+      }
+    }
+
+    // Remove clobbered registers from KnownRegs.
+    for (unsigned i = 0; i < KnownRegs.size();) {
+      if (MI->modifiesRegister(KnownRegs[i].first, TRI) ||
+          (KnownRegs[i].second.IsReg && MI->modifiesRegister(KnownRegs[i].second.U.Reg, TRI))) {
+        KnownRegs[i] = KnownRegs.back();
+        KnownRegs.pop_back();
+      } else {
+        ++i;
+      }
+    }
+    if (KnownRegs.empty())
+      break;
+  }
+
+  if (!Changed)
+    return false;
+
+  // Liveness fixups: clear kill flags along the entire extended live range.
+  for (MCPhysReg Reg : OptimizedRegs) {
+    // Clear kills in BranchMBB from FlagSetter to end (covers CondBr too).
+    for (MachineInstr &MMI :
+         make_range(MachineBasicBlock::iterator(FlagSetter), BranchMBB->end()))
+      MMI.clearRegisterKills(Reg, TRI);
+
+    if (!MBB.isLiveIn(Reg))
+      MBB.addLiveIn(Reg);
+
+    // Clear kills on Path blocks and add live-ins.
+    for (auto *PMBB : Path) {
+      if (!PMBB->isLiveIn(Reg))
+        PMBB->addLiveIn(Reg);
+      for (MachineInstr &MMI : *PMBB)
+        MMI.clearRegisterKills(Reg, TRI);
+    }
+
+    // Clear kills in MBB up to the last change.
+    for (MachineInstr &MMI : make_range(MBB.begin(), LastChange))
+      MMI.clearRegisterKills(Reg, TRI);
+  }
+
+  return true;
+}
+
+bool X86RedundantCopyEliminationImpl::run(MachineFunction &MF) {
+  TII = MF.getSubtarget().getInstrInfo();
+  TRI = MF.getSubtarget().getRegisterInfo();
+
+  bool Changed = false;
+  for (MachineBasicBlock &MBB : MF)
+    Changed |= optimizeBlock(MBB);
+  return Changed;
+}
+
+bool X86RedundantCopyEliminationLegacy::runOnMachineFunction(
+    MachineFunction &MF) {
+  if (skipFunction(MF.getFunction()))
+    return false;
+  return X86RedundantCopyEliminationImpl().run(MF);
+}
+
+} // end anonymous namespace
+
+char X86RedundantCopyEliminationLegacy::ID = 0;
+
+INITIALIZE_PASS(X86RedundantCopyEliminationLegacy, DEBUG_TYPE,
+                "X86 redundant copy elimination pass", false, false)
+
+PreservedAnalyses
+X86RedundantCopyEliminationPass::run(MachineFunction &MF,
+                                     MachineFunctionAnalysisManager &MFAM) {
+  const bool Changed = X86RedundantCopyEliminationImpl().run(MF);
+  if (!Changed)
+    return PreservedAnalyses::all();
+  PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses();
+  PA.preserveSet<CFGAnalyses>();
+  return PA;
+}
+
+FunctionPass *llvm::createX86RedundantCopyEliminationLegacyPass() {
+  return new X86RedundantCopyEliminationLegacy();
+}
diff --git a/llvm/lib/Target/X86/X86TargetMachine.cpp b/llvm/lib/Target/X86/X86TargetMachine.cpp
index 932669b5cbac6..d12133358bc40 100644
--- a/llvm/lib/Target/X86/X86TargetMachine.cpp
+++ b/llvm/lib/Target/X86/X86TargetMachine.cpp
@@ -94,6 +94,7 @@ extern "C" LLVM_C_ABI void LLVMInitializeX86Target() {
   initializeX86SpeculativeLoadHardeningLegacyPass(PR);
   initializeX86SpeculativeExecutionSideEffectSuppressionLegacyPass(PR);
   initializeX86FlagsCopyLoweringLegacyPass(PR);
+  initializeX86RedundantCopyEliminationLegacyPass(PR);
   initializeX86LoadValueInjectionLoadHardeningLegacyPass(PR);
   initializeX86LoadValueInjectionRetHardeningLegacyPass(PR);
   initializeX86OptimizeLEAsLegacyPass(PR);
@@ -539,6 +540,9 @@ void X86PassConfig::addMachineSSAOptimization() {
 }
 
 void X86PassConfig::addPostRegAlloc() {
+  if (getOptLevel() != CodeGenOptLevel::None &&
+      EnableRedundantCopyElimination)
+    addPass(createX86RedundantCopyEliminationLegacyPass());
   addPass(createX86LowerTileCopyLegacyPass());
   addPass(createX86FPStackifierLegacyPass());
   // When -O0 is enabled, the Load Value Injection Hardening pass will fall back
diff --git a/llvm/test/CodeGen/X86/apx/memfold-origVNI-crash.ll b/llvm/test/CodeGen/X86/apx/memfold-origVNI-crash.ll
index d1d23babd33b6..9204cf25d99cc 100644
--- a/llvm/test/CodeGen/X86/apx/memfold-origVNI-crash.ll
+++ b/llvm/test/CodeGen/X86/apx/memfold-origVNI-crash.ll
@@ -29,7 +29,7 @@ define fastcc i64 @foo(ptr %p0, ptr %p1, i64 %p2, i64 %p3, ptr %p4, ptr %p5, ptr
 ; CHECK-NEXT:    testb %al, %al
 ; CHECK-NEXT:  .LBB0_7: # %bb3
 ; CHECK-NEXT:    xorl %eax, %eax
-; CHECK-NEXT:  .LBB0_8: # %cleanup
+; CHECK-NEXT:  .LBB0_8: # %bb19
 ; CHECK-NEXT:    addq $24, %rsp
 ; CHECK-NEXT:    popq %rbx
 ; CHECK-NEXT:    popq %r12
@@ -58,7 +58,7 @@ define fastcc i64 @foo(ptr %p0, ptr %p1, i64 %p2, i64 %p3, ptr %p4, ptr %p5, ptr
 ; CHECK-NEXT:  # %bb.20: # %bb15
 ; CHECK-NEXT:    movl {{[0-9]+}}(%rsp), %eax
 ; CHECK-NEXT:    testl %eax, %eax
-; CHECK-NEXT:    je .LBB0_7
+; CHECK-NEXT:    je .LBB0_8
 ; CHECK-NEXT:  # %bb.21: # %bb15
 ; CHECK-NEXT:    cmpl $2, %eax
 ; CHECK-NEXT:    je .LBB0_7
diff --git a/llvm/test/CodeGen/X86/coalescer-commute3.ll b/llvm/test/CodeGen/X86/coalescer-commute3.ll
index 023a302e51cd2..57506da66a7cd 100644
--- a/llvm/test/CodeGen/X86/coalescer-commute3.ll
+++ b/llvm/test/CodeGen/X86/coalescer-commute3.ll
@@ -13,7 +13,7 @@ define  i32 @perimeter(ptr %tree, i32 %size) nounwind  {
 ; CHECK-NEXT:    je LBB0_3
 ; CHECK-NEXT:  ## %bb.1: ## %entry
 ; CHECK-NEXT:    cmpl $2, %eax
-; CHECK-NEXT:    jne LBB0_3
+; CHECK-NEXT:    jne LBB0_4
 ; CHECK-NEXT:  ## %bb.2: ## %bb
 ; CHECK-NEXT:    movl $0, {{[0-9]+}}(%esp)
 ; CHECK-NEXT:    movl $0, (%esp)
@@ -23,10 +23,10 @@ define  i32 @perimeter(ptr %tree, i32 %size) nounwind  {
 ; CHECK-NEXT:    movl $0, (%esp)
 ; CHECK-NEXT:    calll _perimeter
 ; CHECK-NEXT:    addl %esi, %eax
-; CHECK-NEXT:    jmp LBB0_4
-; CHECK-NEXT:  LBB0_3: ## %UnifiedReturnBlock
-; CHECK-NEXT:    xorl %eax, %eax
+; CHECK-NEXT:    jmp LBB0_3
 ; CHECK-NEXT:  LBB0_4: ## %UnifiedReturnBlock
+; CHECK-NEXT:    xorl %eax, %eax
+; CHECK-NEXT:  LBB0_3: ## %bb50
 ; CHECK-NEXT:    addl $8, %esp
 ; CHECK-NEXT:    popl %esi
 ; CHECK-NEXT:    retl
diff --git a/llvm/test/CodeGen/X86/conditional-tailcall.ll b/llvm/test/CodeGen/X86/conditional-tailcall.ll
index 34f11af756ad0..6b38bf97779e8 100644
--- a/llvm/test/CodeGen/X86/conditional-tailcall.ll
+++ b/llvm/test/CodeGen/X86/conditional-tailcall.ll
@@ -504,7 +504,6 @@ define zeroext i1 @pr31257(ptr nocapture readonly dereferenceable(8) %s) minsize
 ; WIN64-NEXT:    # in Loop: Header=BB3_1 Depth=1
 ; WIN64-NEXT:    movzbl (%rcx), %r9d # encoding: [0x44,0x0f,0xb6,0x09]
 ; WIN64-NEXT:    addl $-48, %r9d # encoding: [0x41,0x83,0xc1,0xd0]
-; WIN64-NEXT:    movl $2, %r8d # encoding: [0x41,0xb8,0x02,0x00,0x00,0x00]
 ; WIN64-NEXT:    cmpl $10, %r9d # encoding: [0x41,0x83,0xf9,0x0a]
 ; WIN64-NEXT:    jae _Z20isValidIntegerSuffixN9__gnu_cxx17__normal_iteratorIPKcSsEES3_ # TAILCALL
 ; WIN64-NEXT:    # encoding: [0x73,A]
diff --git a/llvm/test/CodeGen/X86/llc-pipeline-npm.ll b/llvm/test/CodeGen/X86/llc-pipeline-npm.ll
index ec96575e266e8..b471048e13800 100644
--- a/llvm/test/CodeGen/X86/llc-pipeline-npm.ll
+++ b/llvm/test/CodeGen/X86/llc-pipeline-npm.ll
@@ -163,6 +163,7 @@
 ; O2-NEXT:     stack-slot-coloring
 ; O2-NEXT:     machine-cp
 ; O2-NEXT:     machinelicm
+; O2-NEXT:     x86-copyelim
 ; O2-NEXT:     x86-lower-tile-copy
 ; O2-NEXT:     x86-fp-stackifier
 ; O2-NEXT:     x86-lvi-load
@@ -364,6 +365,7 @@
 ; O3-WINDOWS-NEXT:     stack-slot-coloring
 ; O3-WINDOWS-NEXT:     machine-cp
 ; O3-WINDOWS-NEXT:     machinelicm
+; O3-WINDOWS-NEXT:     x86-copyelim
 ; O3-WINDOWS-NEXT:     x86-lower-tile-copy
 ; O3-WINDOWS-NEXT:     x86-fp-stackifier
 ; O3-WINDOWS-NEXT:     x86-lvi-load
diff --git a/llvm/test/CodeGen/X86/machine-zero-copy-remove.mir b/llvm/test/CodeGen/X86/machine-zero-copy-remove.mir
new file mode 100644
index 0000000000000..8ee457c874bf7
--- /dev/null
+++ b/llvm/test/CodeGen/X86/machine-zero-copy-remove.mir
@@ -0,0 +1,277 @@
+# RUN: llc -mtriple=i386-- -run-pass=x86-copyelim %s -verify-machineinstrs -o - | FileCheck %s
+# RUN: llc -mtriple=i386-- -passes=x86-copyelim %s -o - | FileCheck %s
+---
+# CHECK-LABEL: name: test1
+# CHECK: TEST32rr
+# CHECK: bb.1:
+# CHECK-NOT: MOV32ri
+name:            test1
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $ecx
+
+    TEST32rr killed $eax, killed $eax, implicit-def $eflags
+    JCC_1 %bb.1, 4, implicit killed $eflags
+    JMP_1 %bb.2
+
+  bb.1:
+    liveins: $eax, $ecx
+
+    $eax = MOV32ri 0
+    MOV32mr $ecx, 1, $noreg, 0, $noreg, killed $eax
+
+  bb.2:
+    RET 0
+
+...
+# CHECK-LABEL: name: test2
+# CHECK: TEST32rr
+# CHECK: bb.1:
+# CHECK-NOT: XOR32rr
+name:            test2
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $ecx
+
+    TEST32rr killed $eax, killed $eax, implicit-def $eflags
+    JCC_1 %bb.2, 5, implicit killed $eflags
+    JMP_1 %bb.1
+
+  bb.1:
+    liveins: $eax, $ecx
+
+    $eax = XOR32rr $eax, $eax, implicit-def dead $eflags
+    MOV32mr $ecx, 1, $noreg, 0, $noreg, killed $eax
+
+  bb.2:
+    RET 0
+
+...
+# CHECK-LABEL: name: negative
+# CHECK: MOV32ri
+name:            negative
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $ecx
+
+    TEST32rr killed $eax, killed $eax, implicit-def $eflags
+    JCC_1 %bb.2, 4, implicit killed $eflags
+    JMP_1 %bb.1
+
+  bb.1:
+    liveins: $eax, $ecx
+
+    $eax = MOV32ri 0
+    MOV32mr $ecx, 1, $noreg, 0, $noreg, killed $eax
+
+  bb.2:
+    RET 0
+
+...
+# CHECK-LABEL: name: test3_cmp
+# CHECK: CMP32rr
+# CHECK: bb.1:
+# CHECK-NOT: MOV32rr
+name:            test3_cmp
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $ecx
+
+    CMP32rr $eax, $ecx, implicit-def $eflags
+    JCC_1 %bb.1, 4, implicit killed $eflags
+    JMP_1 %bb.2
+
+  bb.1:
+    liveins: $eax, $ecx
+
+    $eax = MOV32rr $ecx
+    MOV32mr $ecx, 1, $noreg, 0, $noreg, killed $eax
+
+  bb.2:
+    RET 0
+
+...
+# CHECK-LABEL: name: test4_glue
+# CHECK: TEST32rr
+# CHECK: bb.2:
+# CHECK-NOT: MOV32ri
+name:            test4_glue
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $ecx
+
+    TEST32rr killed $eax, killed $eax, implicit-def $eflags
+    JCC_1 %bb.1, 4, implicit killed $eflags
+    JMP_1 %bb.3
+
+  bb.1:
+    liveins: $eax
+
+    JMP_1 %bb.2
+
+  bb.2:
+    liveins: $eax, $ecx
+
+    $eax = MOV32ri 0
+    MOV32mr $ecx, 1, $noreg, 0, $noreg, killed $eax
+
+  bb.3:
+    RET 0
+
+...
+# CHECK-LABEL: name: test5_fallthrough
+# CHECK: TEST32rr
+# CHECK: bb.2:
+# CHECK-NOT: MOV32ri
+name:            test5_fallthrough
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $ecx
+
+    TEST32rr killed $eax, killed $eax, implicit-def $eflags
+    JCC_1 %bb.2, 4, implicit killed $eflags
+
+  bb.1:
+    RET 0
+
+  bb.2:
+    liveins: $eax, $ecx
+
+    $eax = MOV32ri 0
+    MOV32mr $ecx, 1, $noreg, 0, $noreg, killed $eax
+
+...
+# CMP reg, imm: if equal, the register holds the immediate.
+# The MOV32ri 42 in bb.1 is redundant.
+# CHECK-LABEL: name: test6_cmpri
+# CHECK: CMP32ri
+# CHECK: bb.1:
+# CHECK-NOT: MOV32ri
+name:            test6_cmpri
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $ecx
+
+    CMP32ri $eax, 42, implicit-def $eflags
+    JCC_1 %bb.1, 4, implicit killed $eflags
+    JMP_1 %bb.2
+
+  bb.1:
+    liveins: $eax, $ecx
+
+    $eax = MOV32ri 42
+    MOV32mr $ecx, 1, $noreg, 0, $noreg, killed $eax
+
+  bb.2:
+    RET 0
+
+...
+# CMP reg, imm: negative test — wrong immediate value.
+# The MOV32ri 99 must NOT be removed since we know eax==42, not 99.
+# CHECK-LABEL: name: negative_cmpri_wrong_imm
+# CHECK: bb.1:
+# CHECK: MOV32ri
+name:            negative_cmpri_wrong_imm
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $ecx
+
+    CMP32ri $eax, 42, implicit-def $eflags
+    JCC_1 %bb.1, 4, implicit killed $eflags
+    JMP_1 %bb.2
+
+  bb.1:
+    liveins: $eax, $ecx
+
+    $eax = MOV32ri 99
+    MOV32mr $ecx, 1, $noreg, 0, $noreg, killed $eax
+
+  bb.2:
+    RET 0
+
+...
+# SUB reg, reg: if equal, the destination is zero.
+# The MOV32ri 0 in bb.1 is redundant because eax is already zero.
+# CHECK-LABEL: name: test7_sub_eq
+# CHECK: SUB32rr
+# CHECK: bb.1:
+# CHECK-NOT: MOV32ri
+name:            test7_sub_eq
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $edx
+
+    $eax = SUB32rr $eax, $edx, implicit-def $eflags
+    JCC_1 %bb.1, 4, implicit killed $eflags
+    JMP_1 %bb.2
+
+  bb.1:
+    liveins: $eax, $edx
+
+    $eax = MOV32ri 0
+    MOV32mr $edx, 1, $noreg, 0, $noreg, killed $eax
+
+  bb.2:
+    RET 0
+
+...
+# AND self-test: AND eax, eax sets ZF iff eax==0.
+# The MOV32ri 0 is redundant on the equal path.
+# CHECK-LABEL: name: test8_and_self
+# CHECK: AND32rr
+# CHECK: bb.1:
+# CHECK-NOT: MOV32ri
+name:            test8_and_self
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $ecx
+
+    dead $eax = AND32rr $eax, $eax, implicit-def $eflags
+    JCC_1 %bb.1, 4, implicit killed $eflags
+    JMP_1 %bb.2
+
+  bb.1:
+    liveins: $eax, $ecx
+
+    $eax = MOV32ri 0
+    MOV32mr $ecx, 1, $noreg, 0, $noreg, killed $eax
+
+  bb.2:
+    RET 0
+
+...
+# Negative: register clobbered between flag setter and branch.
+# $eax is modified after CMP, so we can't trust the known value.
+# CHECK-LABEL: name: negative_clobbered
+# CHECK: bb.1:
+# CHECK: MOV32rr
+name:            negative_clobbered
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $eax, $ecx, $edx
+
+    CMP32rr $eax, $ecx, implicit-def $eflags
+    $eax = MOV32ri 7
+    JCC_1 %bb.1, 4, implicit killed $eflags
+    JMP_1 %bb.2
+
+  bb.1:
+    liveins: $eax, $ecx, $edx
+
+    $eax = MOV32rr $ecx
+    MOV32mr $ecx, 1, $noreg, 0, $noreg, killed $eax
+
+  bb.2:
+    RET 0
+
diff --git a/llvm/test/CodeGen/X86/opt-pipeline.ll b/llvm/test/CodeGen/X86/opt-pipeline.ll
index 24390f2d852d3..f4724e9d38ae7 100644
--- a/llvm/test/CodeGen/X86/opt-pipeline.ll
+++ b/llvm/test/CodeGen/X86/opt-pipeline.ll
@@ -161,10 +161,12 @@
 ; CHECK-NEXT:       Stack Slot Coloring
 ; CHECK-NEXT:       Machine Copy Propagation Pass
 ; CHECK-NEXT:       Machine Loop Invariant Code Motion
+; CHECK-NEXT:       X86 Redundant Copy Elimination
 ; CHECK-NEXT:       X86 Lower Tile Copy
 ; CHECK-NEXT:       Bundle Machine CFG Edges
 ; CHECK-NEXT:       X86 FP Stackifier
 ; CHECK-NEXT:       MachineDominator Tree Construction
+; CHECK-NEXT:       Machine Natural Loop Construction
 ; CHECK-NEXT:       Machine Dominance Frontier Construction
 ; CHECK-NEXT:       X86 Load Value Injection (LVI) Load Hardening
 ; CHECK-NEXT:       Remove Redundant DEBUG_VALUE analysis
diff --git a/llvm/test/CodeGen/X86/pr38795.ll b/llvm/test/CodeGen/X86/pr38795.ll
index 6a0c13526ac18..08459de69dbfd 100644
--- a/llvm/test/CodeGen/X86/pr38795.ll
+++ b/llvm/test/CodeGen/X86/pr38795.ll
@@ -105,7 +105,6 @@ define dso_local void @fn() {
 ; CHECK-NEXT:    jmp .LBB0_8
 ; CHECK-NEXT:    .p2align 4
 ; CHECK-NEXT:  .LBB0_6: # in Loop: Header=BB0_1 Depth=1
-; CHECK-NEXT:    xorl %edi, %edi
 ; CHECK-NEXT:    movb {{[-0-9]+}}(%e{{[sb]}}p), %dh # 1-byte Reload
 ; CHECK-NEXT:    .p2align 4
 ; CHECK-NEXT:  .LBB0_19: # %for.cond47
@@ -129,7 +128,6 @@ define dso_local void @fn() {
 ; CHECK-NEXT:  # %bb.14: # %if.then31
 ; CHECK-NEXT:    # in Loop: Header=BB0_1 Depth=1
 ; CHECK-NEXT:    xorl %ecx, %ecx
-; CHECK-NEXT:    xorl %ebp, %ebp
 ; CHECK-NEXT:    jmp .LBB0_15
 ; CHECK-NEXT:    .p2align 4
 ; CHECK-NEXT:  .LBB0_9: # in Loop: Header=BB0_1 Depth=1
diff --git a/llvm/test/CodeGen/X86/switch.ll b/llvm/test/CodeGen/X86/switch.ll
index c75819c2fd2c5..a54d3a173a0cb 100644
--- a/llvm/test/CodeGen/X86/switch.ll
+++ b/llvm/test/CodeGen/X86/switch.ll
@@ -960,7 +960,6 @@ define void @optimal_jump_table1(i32 %x) {
 ; CHECK-NEXT:    testl %edi, %edi
 ; CHECK-NEXT:    jne .LBB10_8
 ; CHECK-NEXT:  # %bb.2: # %bb0
-; CHECK-NEXT:    xorl %edi, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
 ; CHECK-NEXT:  .LBB10_8: # %return
 ; CHECK-NEXT:    retq
@@ -1726,41 +1725,38 @@ define void @zero_weight_tree(i32 %x) {
 ; CHECK-NEXT:    jg .LBB18_5
 ; CHECK-NEXT:  # %bb.1: # %entry
 ; CHECK-NEXT:    testl %edi, %edi
-; CHECK-NEXT:    jne .LBB18_2
-; CHECK-NEXT:  # %bb.9: # %bb0
-; CHECK-NEXT:    xorl %edi, %edi
-; CHECK-NEXT:    jmp g at PLT # TAILCALL
+; CHECK-NEXT:    je g at PLT # TAILCALL
+; CHECK-NEXT:  # %bb.2: # %entry
+; CHECK-NEXT:    cmpl $10, %edi
+; CHECK-NEXT:    je .LBB18_9
+; CHECK-NEXT:  # %bb.3: # %entry
+; CHECK-NEXT:    cmpl $20, %edi
+; CHECK-NEXT:    je .LBB18_4
+; CHECK-NEXT:  .LBB18_12: # %return
+; CHECK-NEXT:    retq
 ; CHECK-NEXT:  .LBB18_5: # %entry
 ; CHECK-NEXT:    cmpl $50, %edi
 ; CHECK-NEXT:    jne .LBB18_6
-; CHECK-NEXT:  # %bb.12: # %bb5
+; CHECK-NEXT:  # %bb.11: # %bb5
 ; CHECK-NEXT:    movl $5, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB18_2: # %entry
-; CHECK-NEXT:    cmpl $10, %edi
-; CHECK-NEXT:    je .LBB18_10
-; CHECK-NEXT:  # %bb.3: # %entry
-; CHECK-NEXT:    cmpl $20, %edi
-; CHECK-NEXT:    jne .LBB18_13
-; CHECK-NEXT:  # %bb.4: # %bb2
-; CHECK-NEXT:    movl $2, %edi
-; CHECK-NEXT:    jmp g at PLT # TAILCALL
 ; CHECK-NEXT:  .LBB18_6: # %entry
 ; CHECK-NEXT:    cmpl $30, %edi
-; CHECK-NEXT:    je .LBB18_11
+; CHECK-NEXT:    je .LBB18_10
 ; CHECK-NEXT:  # %bb.7: # %entry
 ; CHECK-NEXT:    cmpl $40, %edi
-; CHECK-NEXT:    je .LBB18_8
-; CHECK-NEXT:  .LBB18_13: # %return
-; CHECK-NEXT:    retq
-; CHECK-NEXT:  .LBB18_10: # %bb1
+; CHECK-NEXT:    jne .LBB18_12
+; CHECK-NEXT:  # %bb.8: # %bb4
+; CHECK-NEXT:    movl $4, %edi
+; CHECK-NEXT:    jmp g at PLT # TAILCALL
+; CHECK-NEXT:  .LBB18_9: # %bb1
 ; CHECK-NEXT:    movl $1, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB18_11: # %bb3
-; CHECK-NEXT:    movl $3, %edi
+; CHECK-NEXT:  .LBB18_4: # %bb2
+; CHECK-NEXT:    movl $2, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB18_8: # %bb4
-; CHECK-NEXT:    movl $4, %edi
+; CHECK-NEXT:  .LBB18_10: # %bb3
+; CHECK-NEXT:    movl $3, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
 ;
 ; NOOPT-LABEL: zero_weight_tree:
@@ -1853,58 +1849,56 @@ define void @left_leaning_weight_balanced_tree(i32 %x) {
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    cmpl $49, %edi
 ; CHECK-NEXT:    jle .LBB19_1
-; CHECK-NEXT:  # %bb.11: # %entry
+; CHECK-NEXT:  # %bb.10: # %entry
 ; CHECK-NEXT:    cmpl $70, %edi
-; CHECK-NEXT:    jne .LBB19_12
-; CHECK-NEXT:  .LBB19_14: # %bb6
+; CHECK-NEXT:    jne .LBB19_11
+; CHECK-NEXT:  .LBB19_13: # %bb6
 ; CHECK-NEXT:    movl $6, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
 ; CHECK-NEXT:  .LBB19_1: # %entry
 ; CHECK-NEXT:    cmpl $9, %edi
-; CHECK-NEXT:    jg .LBB19_4
+; CHECK-NEXT:    jg .LBB19_3
 ; CHECK-NEXT:  # %bb.2: # %entry
 ; CHECK-NEXT:    testl %edi, %edi
-; CHECK-NEXT:    jne .LBB19_18
-; CHECK-NEXT:  # %bb.3: # %bb0
-; CHECK-NEXT:    xorl %edi, %edi
-; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB19_4: # %entry
+; CHECK-NEXT:    je g at PLT # TAILCALL
+; CHECK-NEXT:    jmp .LBB19_17
+; CHECK-NEXT:  .LBB19_3: # %entry
 ; CHECK-NEXT:    cmpl $29, %edi
-; CHECK-NEXT:    jg .LBB19_8
-; CHECK-NEXT:  # %bb.5: # %entry
+; CHECK-NEXT:    jg .LBB19_7
+; CHECK-NEXT:  # %bb.4: # %entry
 ; CHECK-NEXT:    cmpl $10, %edi
-; CHECK-NEXT:    je .LBB19_15
-; CHECK-NEXT:  # %bb.6: # %entry
+; CHECK-NEXT:    je .LBB19_14
+; CHECK-NEXT:  # %bb.5: # %entry
 ; CHECK-NEXT:    cmpl $20, %edi
-; CHECK-NEXT:    jne .LBB19_18
-; CHECK-NEXT:  # %bb.7: # %bb2
+; CHECK-NEXT:    jne .LBB19_17
+; CHECK-NEXT:  # %bb.6: # %bb2
 ; CHECK-NEXT:    movl $2, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB19_12: # %entry
+; CHECK-NEXT:  .LBB19_11: # %entry
 ; CHECK-NEXT:    cmpl $50, %edi
-; CHECK-NEXT:    je .LBB19_17
-; CHECK-NEXT:  # %bb.13: # %entry
+; CHECK-NEXT:    je .LBB19_16
+; CHECK-NEXT:  # %bb.12: # %entry
 ; CHECK-NEXT:    cmpl $60, %edi
-; CHECK-NEXT:    je .LBB19_14
-; CHECK-NEXT:    jmp .LBB19_18
-; CHECK-NEXT:  .LBB19_8: # %entry
+; CHECK-NEXT:    je .LBB19_13
+; CHECK-NEXT:    jmp .LBB19_17
+; CHECK-NEXT:  .LBB19_7: # %entry
 ; CHECK-NEXT:    cmpl $30, %edi
-; CHECK-NEXT:    je .LBB19_16
-; CHECK-NEXT:  # %bb.9: # %entry
+; CHECK-NEXT:    je .LBB19_15
+; CHECK-NEXT:  # %bb.8: # %entry
 ; CHECK-NEXT:    cmpl $40, %edi
-; CHECK-NEXT:    jne .LBB19_18
-; CHECK-NEXT:  # %bb.10: # %bb4
+; CHECK-NEXT:    jne .LBB19_17
+; CHECK-NEXT:  # %bb.9: # %bb4
 ; CHECK-NEXT:    movl $4, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB19_15: # %bb1
+; CHECK-NEXT:  .LBB19_17: # %return
+; CHECK-NEXT:    retq
+; CHECK-NEXT:  .LBB19_14: # %bb1
 ; CHECK-NEXT:    movl $1, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB19_16: # %bb3
+; CHECK-NEXT:  .LBB19_15: # %bb3
 ; CHECK-NEXT:    movl $3, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB19_18: # %return
-; CHECK-NEXT:    retq
-; CHECK-NEXT:  .LBB19_17: # %bb5
+; CHECK-NEXT:  .LBB19_16: # %bb5
 ; CHECK-NEXT:    movl $5, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
 ;
@@ -2027,45 +2021,42 @@ define void @left_leaning_weight_balanced_tree2(i32 %x) {
 ; CHECK-NEXT:  # %bb.6: # %entry
 ; CHECK-NEXT:    cmpl $50, %edi
 ; CHECK-NEXT:    jne .LBB20_7
-; CHECK-NEXT:  # %bb.16: # %bb5
+; CHECK-NEXT:  # %bb.15: # %bb5
 ; CHECK-NEXT:    movl $5, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
 ; CHECK-NEXT:  .LBB20_11: # %entry
 ; CHECK-NEXT:    cmpl $60, %edi
 ; CHECK-NEXT:    je .LBB20_12
-; CHECK-NEXT:    jmp .LBB20_17
+; CHECK-NEXT:    jmp .LBB20_16
 ; CHECK-NEXT:  .LBB20_2: # %entry
 ; CHECK-NEXT:    testl %edi, %edi
-; CHECK-NEXT:    jne .LBB20_3
-; CHECK-NEXT:  # %bb.13: # %bb0
-; CHECK-NEXT:    xorl %edi, %edi
-; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB20_3: # %entry
+; CHECK-NEXT:    je g at PLT # TAILCALL
+; CHECK-NEXT:  # %bb.3: # %entry
 ; CHECK-NEXT:    cmpl $10, %edi
-; CHECK-NEXT:    je .LBB20_14
+; CHECK-NEXT:    je .LBB20_13
 ; CHECK-NEXT:  # %bb.4: # %entry
 ; CHECK-NEXT:    cmpl $20, %edi
-; CHECK-NEXT:    jne .LBB20_17
+; CHECK-NEXT:    jne .LBB20_16
 ; CHECK-NEXT:  # %bb.5: # %bb2
 ; CHECK-NEXT:    movl $2, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
+; CHECK-NEXT:  .LBB20_13: # %bb1
+; CHECK-NEXT:    movl $1, %edi
+; CHECK-NEXT:    jmp g at PLT # TAILCALL
 ; CHECK-NEXT:  .LBB20_7: # %entry
 ; CHECK-NEXT:    cmpl $30, %edi
-; CHECK-NEXT:    je .LBB20_15
+; CHECK-NEXT:    je .LBB20_14
 ; CHECK-NEXT:  # %bb.8: # %entry
 ; CHECK-NEXT:    cmpl $40, %edi
-; CHECK-NEXT:    jne .LBB20_17
+; CHECK-NEXT:    jne .LBB20_16
 ; CHECK-NEXT:  # %bb.9: # %bb4
 ; CHECK-NEXT:    movl $4, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB20_14: # %bb1
-; CHECK-NEXT:    movl $1, %edi
-; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB20_15: # %bb3
+; CHECK-NEXT:  .LBB20_16: # %return
+; CHECK-NEXT:    retq
+; CHECK-NEXT:  .LBB20_14: # %bb3
 ; CHECK-NEXT:    movl $3, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB20_17: # %return
-; CHECK-NEXT:    retq
 ;
 ; NOOPT-LABEL: left_leaning_weight_balanced_tree2:
 ; NOOPT:       # %bb.0: # %entry
@@ -2174,9 +2165,12 @@ define void @right_leaning_weight_balanced_tree(i32 %x) {
 ; CHECK-NEXT:    jg .LBB21_4
 ; CHECK-NEXT:  # %bb.1: # %entry
 ; CHECK-NEXT:    testl %edi, %edi
-; CHECK-NEXT:    jne .LBB21_2
-; CHECK-NEXT:  # %bb.13: # %bb0
-; CHECK-NEXT:    xorl %edi, %edi
+; CHECK-NEXT:    je g at PLT # TAILCALL
+; CHECK-NEXT:  # %bb.2: # %entry
+; CHECK-NEXT:    cmpl $10, %edi
+; CHECK-NEXT:    jne .LBB21_16
+; CHECK-NEXT:  # %bb.3: # %bb1
+; CHECK-NEXT:    movl $1, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
 ; CHECK-NEXT:  .LBB21_4: # %entry
 ; CHECK-NEXT:    cmpl $49, %edi
@@ -2189,38 +2183,31 @@ define void @right_leaning_weight_balanced_tree(i32 %x) {
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
 ; CHECK-NEXT:  .LBB21_5: # %entry
 ; CHECK-NEXT:    cmpl $20, %edi
-; CHECK-NEXT:    je .LBB21_14
+; CHECK-NEXT:    je .LBB21_13
 ; CHECK-NEXT:  # %bb.6: # %entry
 ; CHECK-NEXT:    cmpl $30, %edi
-; CHECK-NEXT:    je .LBB21_15
+; CHECK-NEXT:    je .LBB21_14
 ; CHECK-NEXT:  # %bb.7: # %entry
 ; CHECK-NEXT:    cmpl $40, %edi
-; CHECK-NEXT:    jne .LBB21_17
+; CHECK-NEXT:    jne .LBB21_16
 ; CHECK-NEXT:  # %bb.8: # %bb4
 ; CHECK-NEXT:    movl $4, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
 ; CHECK-NEXT:  .LBB21_10: # %entry
 ; CHECK-NEXT:    cmpl $50, %edi
-; CHECK-NEXT:    je .LBB21_16
+; CHECK-NEXT:    je .LBB21_15
 ; CHECK-NEXT:  # %bb.11: # %entry
 ; CHECK-NEXT:    cmpl $60, %edi
 ; CHECK-NEXT:    je .LBB21_12
-; CHECK-NEXT:    jmp .LBB21_17
-; CHECK-NEXT:  .LBB21_14: # %bb2
+; CHECK-NEXT:  .LBB21_16: # %return
+; CHECK-NEXT:    retq
+; CHECK-NEXT:  .LBB21_13: # %bb2
 ; CHECK-NEXT:    movl $2, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB21_15: # %bb3
+; CHECK-NEXT:  .LBB21_14: # %bb3
 ; CHECK-NEXT:    movl $3, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB21_2: # %entry
-; CHECK-NEXT:    cmpl $10, %edi
-; CHECK-NEXT:    jne .LBB21_17
-; CHECK-NEXT:  # %bb.3: # %bb1
-; CHECK-NEXT:    movl $1, %edi
-; CHECK-NEXT:    jmp g at PLT # TAILCALL
-; CHECK-NEXT:  .LBB21_17: # %return
-; CHECK-NEXT:    retq
-; CHECK-NEXT:  .LBB21_16: # %bb5
+; CHECK-NEXT:  .LBB21_15: # %bb5
 ; CHECK-NEXT:    movl $5, %edi
 ; CHECK-NEXT:    jmp g at PLT # TAILCALL
 ;
diff --git a/llvm/utils/gn/secondary/llvm/lib/Target/X86/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Target/X86/BUILD.gn
index 512041f6dbe00..ba8d8b14d6268 100644
--- a/llvm/utils/gn/secondary/llvm/lib/Target/X86/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/Target/X86/BUILD.gn
@@ -146,6 +146,7 @@ static_library("LLVMX86CodeGen") {
     "X86FixupSetCC.cpp",
     "X86FixupVectorConstants.cpp",
     "X86FlagsCopyLowering.cpp",
+    "X86RedundantCopyElimination.cpp",
     "X86FloatingPoint.cpp",
     "X86FrameLowering.cpp",
     "X86GlobalBaseReg.cpp",



More information about the llvm-commits mailing list