[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